kernel/eka/memmodel/epoc/flexible/mmu/mdatapaging.cpp
changeset 0 a41df078684a
child 22 2f92ad2dc5db
--- /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 <plat_priv.h>
+#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<TThreadMessage*>(&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<TThreadMessage*>(&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);
+	}
+