diff -r 000000000000 -r a41df078684a kernel/eka/memmodel/epoc/flexible/mmu/mdatapaging.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/memmodel/epoc/flexible/mmu/mdatapaging.cpp Mon Oct 19 15:55:17 2009 +0100 @@ -0,0 +1,712 @@ +// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// + +#include +#include "mm.h" +#include "mmu.h" + +#include "mmanager.h" +#include "mobject.h" +#include "mmapping.h" +#include "mpager.h" +#include "mswap.h" + + +/** +Manages the swap via the data paging device. +*/ +class DSwapManager + { +public: + + enum TSwapFlags + { + EAllocated = 1 << 0, + EUninitialised = 1 << 1, + ESaved = 1 << 2, + ESwapFlagsMask = 0x7, + + ESwapIndexShift = 3, + ESwapIndexMask = 0xffffffff << ESwapIndexShift, + }; + + TInt Create(DPagingDevice* aDevice); + + TInt ReserveSwap(DMemoryObject* aMemory, TUint aStartIndex, TUint aPageCount); + TInt UnreserveSwap(DMemoryObject* aMemory, TUint aStartIndex, TUint aPageCount); + TBool IsReserved(DMemoryObject* aMemory, TUint aStartIndex, TUint aPageCount); + + TInt ReadSwapPages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TLinAddr aLinAddr, DPageReadRequest* aRequest, TPhysAddr* aPhysAddrs); + TInt WriteSwapPages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TLinAddr aLinAddr, DPageWriteRequest* aRequest); + void DoDeleteNotify(TUint aSwapData); + + void GetSwapInfo(SVMSwapInfo& aInfoOut); + TInt SetSwapThresholds(const SVMSwapThresholds& aThresholds); + void CheckSwapThresholds(TUint aInitial, TUint aFinal); + +protected: + DPagingDevice* iDevice; + TBitMapAllocator* iBitMap; + TUint iBitMapFree; + TUint iAllocOffset; + TUint iSwapThesholdLow; + TUint iSwapThesholdGood; + TThreadMessage iDelNotifyMsg; + }; + + +/** +Manager for demand paged memory objects which contain writeable data. +The contents of the memory are written to a backing store whenever its +pages are 'paged out'. + +@see DSwapManager +*/ +class DDataPagedMemoryManager : public DPagedMemoryManager + { +private: + // from DMemoryManager... + virtual TInt Alloc(DMemoryObject* aMemory, TUint aIndex, TUint aCount); + virtual void Free(DMemoryObject* aMemory, TUint aIndex, TUint aCount); + virtual TInt Wipe(DMemoryObject* aMemory); + virtual TInt CleanPage(DMemoryObject* aMemory, SPageInfo* aPageInfo, TPhysAddr*& aPageArrayEntry); + + // Methods inherited from DPagedMemoryManager + virtual void Init3(); + virtual TInt InstallPagingDevice(DPagingDevice* aDevice); + virtual TInt AcquirePageReadRequest(DPageReadRequest*& aRequest, DMemoryObject* aMemory, TUint aIndex, TUint aCount); + virtual TInt AcquirePageWriteRequest(DPageWriteRequest*& aRequest, DMemoryObject* aMemory, TUint aIndex, TUint aCount); + virtual TInt ReadPages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TPhysAddr* aPages, DPageReadRequest* aRequest); + virtual TInt WritePages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TPhysAddr* aPages, DPageWriteRequest* aRequest); + virtual TBool IsAllocated(DMemoryObject* aMemory, TUint aIndex, TUint aCount); + +public: + void GetSwapInfo(SVMSwapInfo& aInfoOut); + TInt SetSwapThresholds(const SVMSwapThresholds& aThresholds); + +private: + /** + The paging device used for accessing the backing store. + This is set by #InstallPagingDevice. + */ + DPagingDevice* iDevice; + + /** + The instance of #DSwapManager being used by this manager. + */ + DSwapManager* iSwapManager; + +public: + /** + The single instance of this manager class. + */ + static DDataPagedMemoryManager TheManager; + }; + + +DDataPagedMemoryManager DDataPagedMemoryManager::TheManager; +DPagedMemoryManager* TheDataPagedMemoryManager = &DDataPagedMemoryManager::TheManager; + + +/** +Create a swap manager. + +@param aDevice The demand paging device for access to the swap. +*/ +TInt DSwapManager::Create(DPagingDevice* aDevice) + { + __ASSERT_COMPILE(!(ESwapIndexMask & ESwapFlagsMask)); + __NK_ASSERT_DEBUG(iDevice == NULL); + iDevice = aDevice; + + // Create the structures required to track the swap usage. + TUint swapPages = (iDevice->iSwapSize << iDevice->iReadUnitShift) >> KPageShift; + // Can't have more swap pages than we can map. + __NK_ASSERT_DEBUG(swapPages<=DMemoryObject::KMaxPagingManagerData); + __NK_ASSERT_DEBUG(swapPages<=(KMaxTUint>>ESwapIndexShift)); + + if ((TheMmu.TotalPhysicalRamPages() << 2) < swapPages) + {// The swap is limited to a maximum of 4 times the amount of RAM. + return KErrTooBig; + } + + iBitMap = TBitMapAllocator::New(swapPages, ETrue); + if (iBitMap == NULL) + {// Not enough RAM to keep track of the swap. + return KErrNoMemory; + } + iBitMapFree = swapPages; + iAllocOffset = 0; + return KErrNone; + } + + +/** +Reserve some swap pages for the requested region of the memory object + +@param aMemory The memory object to reserve pages for. +@param aStartIndex The page index in the memory object of the start of the region. +@param aPageCount The number of pages to reserve. + +@return KErrNone on success, KErrNoMemory if not enough swap space available. +@pre aMemory's lock is held. +@post aMemory's lock is held. +*/ +TInt DSwapManager::ReserveSwap(DMemoryObject* aMemory, TUint aStartIndex, TUint aPageCount) + { + __NK_ASSERT_DEBUG(MemoryObjectLock::IsHeld(aMemory)); + __NK_ASSERT_DEBUG(RamAllocLock::IsHeld()); + + const TUint indexEnd = aStartIndex + aPageCount; + TUint index = aStartIndex; + +#ifdef _DEBUG + for (; index < indexEnd; index++) + {// This page shouldn't already be in use. + MmuLock::Lock(); + __NK_ASSERT_DEBUG(!(aMemory->PagingManagerData(index) & ESwapFlagsMask)); + MmuLock::Unlock(); + } +#endif + + if (iBitMapFree < aPageCount) + { + Kern::AsyncNotifyChanges(EChangesOutOfMemory); + return KErrNoMemory; + } + // Reserve the required swap space and mark each page as allocated and uninitialised. + TUint initFree = iBitMapFree; + iBitMapFree -= aPageCount; + for (index = aStartIndex; index < indexEnd; index++) + { + // Grab MmuLock to stop manager data being accessed. + MmuLock::Lock(); + TUint swapData = aMemory->PagingManagerData(index); + __NK_ASSERT_DEBUG(!(swapData & EAllocated)); + swapData = EAllocated | EUninitialised; + aMemory->SetPagingManagerData(index, swapData); + MmuLock::Unlock(); + } + + CheckSwapThresholds(initFree, iBitMapFree); + return KErrNone; + } + + +/** +Unreserve swap pages for the requested region of the memory object. + +@param aMemory The memory object to unreserve pages for. +@param aStartIndex The page index in the memory object of the start of the region. +@param aPageCount The number of pages to unreserve. + +@return The number of pages freed. +@pre aMemory's lock is held. +@post aMemory's lock is held. +*/ +TInt DSwapManager::UnreserveSwap(DMemoryObject* aMemory, TUint aStartIndex, TUint aPageCount) + { + __NK_ASSERT_DEBUG(MemoryObjectLock::IsHeld(aMemory)); + __NK_ASSERT_DEBUG(RamAllocLock::IsHeld()); + + TUint initFree = iBitMapFree; + TUint freedPages = 0; + const TUint indexEnd = aStartIndex + aPageCount; + for (TUint index = aStartIndex; index < indexEnd; index++) + { + // Grab MmuLock to stop manager data being accessed. + MmuLock::Lock(); + TUint swapData = aMemory->PagingManagerData(index); + TUint swapIndex = swapData >> ESwapIndexShift; + TBool notifyDelete = EFalse; + if (swapData & EAllocated) + { + if (swapData & ESaved) + { + notifyDelete = ETrue; + iBitMap->Free(swapIndex); + } + freedPages++; + aMemory->SetPagingManagerData(index, 0); + } +#ifdef _DEBUG + else + __NK_ASSERT_DEBUG(swapData == 0); +#endif + + MmuLock::Unlock(); + + if (notifyDelete) + DoDeleteNotify(swapIndex); + } + iBitMapFree += freedPages; + CheckSwapThresholds(initFree, iBitMapFree); + return freedPages; + } + + +/** +Determine whether the specified pages in the memory object have swap reserved for them. + +@param aMemory The memory object that owns the pages. +@param aStartIndex The first index of the pages to check. +@param aPageCount The number of pages to check. + +@return ETrue if swap is reserved for all the pages, EFalse otherwise. +*/ +TBool DSwapManager::IsReserved(DMemoryObject* aMemory, TUint aStartIndex, TUint aPageCount) + {// MmuLock required to protect manager data. + __NK_ASSERT_DEBUG(MmuLock::IsHeld()); + __NK_ASSERT_DEBUG(aStartIndex < aMemory->iSizeInPages); + __NK_ASSERT_DEBUG(aStartIndex + aPageCount <= aMemory->iSizeInPages); + + const TUint indexEnd = aStartIndex + aPageCount; + for (TUint index = aStartIndex; index < indexEnd; index++) + { + if (!(aMemory->PagingManagerData(index) & DSwapManager::EAllocated)) + {// This page is not allocated by swap manager. + return EFalse; + } + } + return ETrue; + } + + +/** +Read from the swap the specified pages associated with the memory object. + +@param aMemory The memory object to read the pages for +@param aIndex The index of the first page within the memory object. +@param aCount The number of pages to read. +@param aLinAddr The address to copy the pages to. +@param aRequest The request to use for the read. +@param aPhysAddrs An array of the physical addresses for each page to read in. +*/ +TInt DSwapManager::ReadSwapPages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TLinAddr aLinAddr, DPageReadRequest* aRequest, TPhysAddr* aPhysAddrs) + { + TInt r = KErrNone; + const TUint readUnitShift = iDevice->iReadUnitShift; + TUint readSize = KPageSize >> readUnitShift; + TThreadMessage* msg = const_cast(&aRequest->iMessage); + + // Determine the wipe byte values for uninitialised pages. + TUint allocFlags = aMemory->RamAllocFlags(); + TBool wipePages = !(allocFlags & Mmu::EAllocNoWipe); + TUint8 wipeByte = (allocFlags & Mmu::EAllocUseCustomWipeByte) ? (allocFlags >> Mmu::EAllocWipeByteShift) & 0xff : 0x03; + + const TUint indexEnd = aIndex + aCount; + for (TUint index = aIndex; index < indexEnd; index++, aLinAddr += KPageSize, aPhysAddrs++) + { + START_PAGING_BENCHMARK; + + MmuLock::Lock(); // MmuLock required for atomic access to manager data. + TUint swapData = aMemory->PagingManagerData(index); + + if (!(swapData & EAllocated)) + {// This page is not committed to the memory object + MmuLock::Unlock(); + return KErrNotFound; + } + if (swapData & EUninitialised) + {// This page has not been written to yet so don't read from swap + // just wipe it if required. + MmuLock::Unlock(); + if (wipePages) + { + memset((TAny*)aLinAddr, wipeByte, KPageSize); + } + } + else + { + __NK_ASSERT_DEBUG(swapData & ESaved); + TUint swapIndex = swapData >> ESwapIndexShift; + // OK to release as if the object's data is decommitted the pager + // will check that data is still valid before mapping it. + MmuLock::Unlock(); + TUint readStart = (swapIndex << KPageShift) >> readUnitShift; + START_PAGING_BENCHMARK; + r = iDevice->Read(msg, aLinAddr, readStart, readSize, DPagingDevice::EDriveDataPaging); + if (r != KErrNone) + __KTRACE_OPT(KPANIC, Kern::Printf("DSwapManager::ReadSwapPages: error reading media at %08x + %x: %d", readStart << readUnitShift, readSize << readUnitShift, r)); + __NK_ASSERT_DEBUG(r!=KErrNoMemory); // not allowed to allocate memory, therefore can't fail with KErrNoMemory + END_PAGING_BENCHMARK(EPagingBmReadDataMedia); + // TODO: Work out what to do if page in fails, unmap all pages???? + __NK_ASSERT_ALWAYS(r == KErrNone); + } + END_PAGING_BENCHMARK(EPagingBmReadDataPage); + } + + return r; + } + + +/** +Write the specified memory object's pages from the RAM into the swap. + +@param aMemory The memory object who owns the pages. +@param aIndex The index within the memory object. +@param aCount The number of pages to write out. +@param aLinAddr The location of the pages to write out. +@param aRequest The demand paging request to use. + +*/ +TInt DSwapManager::WriteSwapPages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TLinAddr aLinAddr, DPageWriteRequest* aRequest) + {// The RamAllocLock prevents the object's swap pages being reassigned. + __NK_ASSERT_DEBUG(RamAllocLock::IsHeld()); + + // Write the page out to the swap. + TInt r = KErrNone; + const TUint readUnitShift = iDevice->iReadUnitShift; + TUint writeSize = KPageSize >> readUnitShift; + TThreadMessage* msg = const_cast(&aRequest->iMessage); + + const TUint indexEnd = aIndex + aCount; + for (TUint index = aIndex; index < indexEnd; index++) + { + START_PAGING_BENCHMARK; + + MmuLock::Lock(); + TUint swapData = aMemory->PagingManagerData(index); + // OK to release as ram alloc lock prevents manager data being updated. + MmuLock::Unlock(); + if (!(swapData & EAllocated)) + {// This page is being decommited from aMemory so it is clean/unrequired. + continue; + } + TInt swapIndex = swapData >> ESwapIndexShift; + if (swapData & ESaved) + {// An old version of this page has been saved to swap so free it now + // as it will be out of date. + iBitMap->Free(swapIndex); + DoDeleteNotify(swapIndex); + } + // Get a new swap location for this page. + swapIndex = iBitMap->AllocFrom(iAllocOffset); + __NK_ASSERT_DEBUG(swapIndex != -1 && swapIndex < iBitMap->iSize); + iAllocOffset = swapIndex + 1; + if (iAllocOffset == (TUint)iBitMap->iSize) + iAllocOffset = 0; + + TUint writeOffset = (swapIndex << KPageShift) >> readUnitShift; + { + START_PAGING_BENCHMARK; + r = iDevice->Write(msg, aLinAddr, writeOffset, writeSize, EFalse); + if (r != KErrNone) + __KTRACE_OPT(KPANIC, Kern::Printf("DSwapManager::WriteSwapPages: error writing media at %08x + %x: %d", writeOffset << readUnitShift, writeSize << readUnitShift, r)); + __NK_ASSERT_DEBUG(r!=KErrNoMemory); // not allowed to allocate memory, therefore can't fail with KErrNoMemory + END_PAGING_BENCHMARK(EPagingBmWriteDataMedia); + } + // TODO: Work out what to do if page out fails. + __NK_ASSERT_ALWAYS(r == KErrNone); + MmuLock::Lock(); + // The swap data should not have been modified. + __NK_ASSERT_DEBUG(swapData == aMemory->PagingManagerData(index)); + // Store the new swap location and mark the page as saved. + swapData &= ~(EUninitialised | ESwapIndexMask); + swapData |= (swapIndex << ESwapIndexShift) | ESaved; + aMemory->SetPagingManagerData(index, swapData); + MmuLock::Unlock(); + + END_PAGING_BENCHMARK(EPagingBmWriteDataPage); + } + + return r; + } + + +/** +Notify the media driver that the page written to swap is no longer required. +*/ +void DSwapManager::DoDeleteNotify(TUint aSwapIndex) + { + // Ram Alloc lock prevents the swap location being assigned to another page. + __NK_ASSERT_DEBUG(RamAllocLock::IsHeld()); + +#ifdef __PAGING_DELETE_NOTIFY_ENABLED + const TUint readUnitShift = iDevice->iReadUnitShift; + const TUint size = KPageSize >> readUnitShift; + TUint offset = (aSwapIndex << KPageShift) >> readUnitShift; + + START_PAGING_BENCHMARK; + // Ignore the return value as this is just an optimisation that is not supported on all media. + (void)iDevice->DeleteNotify(&iDelNotifyMsg, offset, size); + END_PAGING_BENCHMARK(EPagingBmDeleteNotifyDataPage); +#endif + } + + +// Check swap thresholds and notify (see K::CheckFreeMemoryLevel) +void DSwapManager::CheckSwapThresholds(TUint aInitial, TUint aFinal) + { + TUint changes = 0; + if (aFinal < iSwapThesholdLow && aInitial >= iSwapThesholdLow) + changes |= (EChangesFreeMemory | EChangesLowMemory); + if (aFinal >= iSwapThesholdGood && aInitial < iSwapThesholdGood) + changes |= EChangesFreeMemory; + if (changes) + Kern::AsyncNotifyChanges(changes); + } + + +void DSwapManager::GetSwapInfo(SVMSwapInfo& aInfoOut) + { + __NK_ASSERT_DEBUG(RamAllocLock::IsHeld()); + aInfoOut.iSwapSize = iBitMap->iSize << KPageShift; + aInfoOut.iSwapFree = iBitMapFree << KPageShift; + } + + +TInt DSwapManager::SetSwapThresholds(const SVMSwapThresholds& aThresholds) + { + __NK_ASSERT_DEBUG(RamAllocLock::IsHeld()); + if (aThresholds.iLowThreshold > aThresholds.iGoodThreshold) + return KErrArgument; + TInt low = (aThresholds.iLowThreshold + KPageSize - 1) >> KPageShift; + TInt good = (aThresholds.iGoodThreshold + KPageSize - 1) >> KPageShift; + if (good > iBitMap->iSize) + return KErrArgument; + iSwapThesholdLow = low; + iSwapThesholdGood = good; + return KErrNone; + } + + + +TInt DDataPagedMemoryManager::InstallPagingDevice(DPagingDevice* aDevice) + { + TRACEB(("DDataPagedMemoryManager::InstallPagingDevice(0x%08x)",aDevice)); + + TUint dataPolicy = TheSuperPage().KernelConfigFlags() & EKernelConfigDataPagingPolicyMask; + TRACEB(("Data Paging Policy = %d", dataPolicy >> EKernelConfigDataPagingPolicyShift)); + if (dataPolicy == EKernelConfigDataPagingPolicyNoPaging) + {// No paging allowed so don't register the device. + return KErrNone; + } + + // Store the device, blocking any other devices from installing. + if (!NKern::CompareAndSwap((TAny*&)iDevice, (TAny*)NULL, (TAny*)aDevice)) + {// Data paging device already installed. + __KTRACE_OPT2(KPAGING,KBOOT,Kern::Printf("**** Attempt to install more than one data paging device !!!!!!!! ****")); + return KErrAlreadyExists; + } + + // Now we can determine the size of the swap, create the swap manager. + iSwapManager = new DSwapManager; + __NK_ASSERT_ALWAYS(iSwapManager); + + TInt r = iSwapManager->Create(iDevice); + if (r != KErrNone) + {// Couldn't create the swap manager. + delete iSwapManager; + iSwapManager = NULL; + NKern::SafeSwap(NULL, (TAny*&)iDevice); + return r; + } + NKern::LockedSetClear(K::MemModelAttributes, 0, EMemModelAttrDataPaging); + + return r; + } + + +TInt DDataPagedMemoryManager::AcquirePageReadRequest(DPageReadRequest*& aRequest, DMemoryObject* aMemory, TUint aIndex, TUint aCount) + { + aRequest = iDevice->iRequestPool->AcquirePageReadRequest(aMemory,aIndex,aCount); + return KErrNone; + } + + +TInt DDataPagedMemoryManager::AcquirePageWriteRequest(DPageWriteRequest*& aRequest, DMemoryObject* aMemory, TUint aIndex, TUint aCount) + { + aRequest = iDevice->iRequestPool->AcquirePageWriteRequest(aMemory,aIndex,aCount); + return KErrNone; + } + + +void DDataPagedMemoryManager::Init3() + { + } + + +TInt DDataPagedMemoryManager::Alloc(DMemoryObject* aMemory, TUint aIndex, TUint aCount) + { + __NK_ASSERT_DEBUG(MemoryObjectLock::IsHeld(aMemory)); + + // re-initialise any decommitted pages which we may still own because they were pinned... + ReAllocDecommitted(aMemory,aIndex,aCount); + + // Reserve the swap pages required. + RamAllocLock::Lock(); + TInt r = iSwapManager->ReserveSwap(aMemory, aIndex, aCount); + RamAllocLock::Unlock(); + + return r; + } + + +void DDataPagedMemoryManager::Free(DMemoryObject* aMemory, TUint aIndex, TUint aCount) + { + TRACE2(("DDataPagedMemoryManager::Free(0x%08x,0x%x,0x%x)", aMemory, aIndex, aCount)); + __NK_ASSERT_DEBUG(MemoryObjectLock::IsHeld(aMemory)); + + // Unreserve the swap pages associated with the memory object. Do this before + // removing the page array entries to prevent a page fault reallocating these pages. + RamAllocLock::Lock(); + TInt freed = iSwapManager->UnreserveSwap(aMemory, aIndex, aCount); + (void)freed; + RamAllocLock::Unlock(); + + DoFree(aMemory,aIndex,aCount); + } + + +/** +@copydoc DMemoryManager::Wipe +@todo Not yet implemented. + Need to handle this smartly, e.g. throw RAM away and set to uninitialised +*/ +TInt DDataPagedMemoryManager::Wipe(DMemoryObject* aMemory) + { + __NK_ASSERT_ALWAYS(0); // not implemented yet + + return KErrNotSupported; + } + + +TInt DDataPagedMemoryManager::ReadPages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TPhysAddr* aPages, DPageReadRequest* aRequest) + { + __NK_ASSERT_DEBUG(aRequest->CheckUse(aMemory,aIndex,aCount)); + + // Map pages temporarily so that we can copy into them. + const TLinAddr linAddr = aRequest->MapPages(aIndex, aCount, aPages); + + TInt r = iSwapManager->ReadSwapPages(aMemory, aIndex, aCount, linAddr, aRequest, aPages); + + // The memory object allows executable mappings then need IMB. + aRequest->UnmapPages(aMemory->IsExecutable()); + + return r; + } + + +TInt DDataPagedMemoryManager::WritePages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TPhysAddr* aPages, DPageWriteRequest* aRequest) + { + __NK_ASSERT_DEBUG(aRequest->CheckUse(aMemory,aIndex,aCount)); + + // Map pages temporarily so that we can copy into them. + const TLinAddr linAddr = aRequest->MapPages(aIndex, aCount, aPages); + + TInt r = iSwapManager->WriteSwapPages(aMemory, aIndex, aCount, linAddr, aRequest); + + // The memory object allows executable mappings then need IMB. + aRequest->UnmapPages(aMemory->IsExecutable()); + + return r; + } + + +TInt DDataPagedMemoryManager::CleanPage(DMemoryObject* aMemory, SPageInfo* aPageInfo, TPhysAddr*& aPageArrayEntry) + { + if(aPageInfo->IsDirty()==false) + return KErrNone; + + // shouldn't be asked to clean a page which is writable... + __NK_ASSERT_DEBUG(aPageInfo->IsWritable()==false); + + // mark page as being modified by us... + TUint modifierInstance; // dummy variable used only for it's storage address on the stack + aPageInfo->SetModifier(&modifierInstance); + + // get info about page... + TUint index = aPageInfo->Index(); + TPhysAddr physAddr = aPageInfo->PhysAddr(); + + // Release the mmu lock while we write out the page. This is safe as the + // RamAllocLock stops the physical address being freed from this object. + MmuLock::Unlock(); + + // get paging request object... + DPageWriteRequest* req; + TInt r = AcquirePageWriteRequest(req, aMemory, index, 1); + __NK_ASSERT_DEBUG(r==KErrNone); // we should always get a write request because the previous function blocks until it gets one + __NK_ASSERT_DEBUG(req); // we should always get a write request because the previous function blocks until it gets one + + r = WritePages(aMemory, index, 1, &physAddr, req); + + req->Release(); + + MmuLock::Lock(); + + if(r!=KErrNone) + return r; + + // check if page is clean... + if(aPageInfo->CheckModified(&modifierInstance) || aPageInfo->IsWritable()) + { + // someone else modified the page, or it became writable, so fail... + r = KErrInUse; + } + else + { + // page is now clean! + ThePager.SetClean(*aPageInfo); + } + + return r; + } + + +TBool DDataPagedMemoryManager::IsAllocated(DMemoryObject* aMemory, TUint aIndex, TUint aCount) + {// MmuLock required to protect manager data. + // DPagedMemoryManager::DoPageInDone() won't allow MmuLock to be released + // so can only cope with a maximum of KMaxPagesInOneGo. + __NK_ASSERT_DEBUG(MmuLock::IsHeld()); + __NK_ASSERT_DEBUG(aCount <= KMaxPagesInOneGo); + + return iSwapManager->IsReserved(aMemory, aIndex, aCount); + } + + +void DDataPagedMemoryManager::GetSwapInfo(SVMSwapInfo& aInfoOut) + { + NKern::ThreadEnterCS(); + RamAllocLock::Lock(); + iSwapManager->GetSwapInfo(aInfoOut); + RamAllocLock::Unlock(); + NKern::ThreadLeaveCS(); + } + + +TInt DDataPagedMemoryManager::SetSwapThresholds(const SVMSwapThresholds& aThresholds) + { + NKern::ThreadEnterCS(); + RamAllocLock::Lock(); + TInt r = iSwapManager->SetSwapThresholds(aThresholds); + RamAllocLock::Unlock(); + NKern::ThreadLeaveCS(); + return r; + } + + +void GetSwapInfo(SVMSwapInfo& aInfoOut) + { + ((DDataPagedMemoryManager*)TheDataPagedMemoryManager)->GetSwapInfo(aInfoOut); + } + + +TInt SetSwapThresholds(const SVMSwapThresholds& aThresholds) + { + return ((DDataPagedMemoryManager*)TheDataPagedMemoryManager)->SetSwapThresholds(aThresholds); + } +