kernel/eka/memmodel/epoc/flexible/mmu/mdefrag.cpp
changeset 0 a41df078684a
child 26 c734af59ce98
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/memmodel/epoc/flexible/mmu/mdefrag.cpp	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,165 @@
+// Copyright (c) 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 <memmodel.h>
+#include <ramalloc.h>
+#include "mm.h"
+#include "mmu.h"
+#include "mmanager.h"
+#include "mobject.h"
+#include "mpager.h"
+#include "mmapping.h"
+
+
+TInt M::RamDefragFault(TAny* /*aExceptionInfo*/)
+	{// Defag faults are handled by Mmu::HandlePageFault() on the flexible memory model.
+	return KErrAbort;
+	} 
+
+
+EXPORT_C TInt Epoc::MovePhysicalPage(TPhysAddr aOld, TPhysAddr& aNew, TRamDefragPageToMove aPageToMove)
+	{
+	CHECK_PRECONDITIONS(MASK_THREAD_CRITICAL,"Epoc::MovePhysicalPage");
+	__KTRACE_OPT(KMMU,Kern::Printf("Epoc::MovePhysicalPage() old=%08x pageToMove=%d",aOld,aPageToMove));
+	// Mark aNew as invalid if a page is moved then this will be updated.
+	// However, if the page couldn't be moved or is discarded then it must be invalid.
+	aNew = KPhysAddrInvalid;
+
+	TInt r = KErrNotFound;
+
+	switch (aPageToMove)
+		{
+		case ERamDefragPage_Physical :
+			break;
+
+		case ERamDefragPage_PageTable :
+			{
+			// Assume aOld is a linear address in current thread and get the physical
+			// address of the page table that maps it and move that.
+			TLinAddr linAddr = (TLinAddr) aOld;
+			DMemModelThread* thread = (DMemModelThread*)TheCurrentThread;
+			// Get the os asid of current thread's process so no need to open reference on it.
+			TUint osAsid = ((DMemModelProcess*)thread->iOwningProcess)->OsAsid();
+			TUint offsetInMapping;
+			TUint mapInstanceCount;
+			DMemoryMapping* mapping = MM::FindMappingInAddressSpace(osAsid,linAddr,1,offsetInMapping,mapInstanceCount);
+			if (!mapping)
+				return r;
+			MmuLock::Lock();
+			TUint memoryIndex = (offsetInMapping >> KPageShift)+ mapping->iStartIndex;
+			TPte* pte = mapping->FindPageTable(linAddr, memoryIndex);
+			if (mapInstanceCount != mapping->MapInstanceCount() || !pte)
+				{
+				MmuLock::Unlock();
+				mapping->Close();
+				return r;
+				}
+			TPhysAddr physAddr = TheMmu.LinearToPhysical((TLinAddr)pte, KKernelOsAsid);
+			__NK_ASSERT_DEBUG(physAddr != KPhysAddrInvalid);
+			aOld = physAddr;	// Have physical address of page table page so move it.
+			MmuLock::Unlock();
+			mapping->Close();
+			break;
+			}
+
+		case ERamDefragPage_PageTableInfo :
+			{
+			// Assume aOld is a linear address in current thread and get physical 
+			// address of the page table info of the page table that maps it 
+			// and move that.
+			TLinAddr linAddr = (TLinAddr) aOld;
+			DMemModelThread* thread = (DMemModelThread*)TheCurrentThread;
+			// Get the os asid of current thread's process so no need to open reference on it.
+			TUint osAsid = ((DMemModelProcess*)thread->iOwningProcess)->OsAsid();
+			TUint offsetInMapping;
+			TUint mapInstanceCount;
+			DMemoryMapping* mapping = MM::FindMappingInAddressSpace(osAsid,linAddr,1,offsetInMapping,mapInstanceCount);
+			if (!mapping)
+				return r;
+			MmuLock::Lock();
+			TUint memoryIndex = (offsetInMapping >> KPageShift)+ mapping->iStartIndex;
+			TPte* pte = mapping->FindPageTable(linAddr, memoryIndex);
+			if (mapInstanceCount != mapping->MapInstanceCount() || !pte)
+				{
+				MmuLock::Unlock();
+				mapping->Close();
+				return r;
+				}
+			
+			SPageTableInfo* pti = SPageTableInfo::FromPtPtr(pte);
+			TPhysAddr physAddr = TheMmu.LinearToPhysical((TLinAddr)pti, KKernelOsAsid);
+			__NK_ASSERT_DEBUG(physAddr != KPhysAddrInvalid);
+			aOld = physAddr;	// Have physical address of page table info page so move it.
+			MmuLock::Unlock();
+			mapping->Close();
+			break;
+			}
+
+		default :
+			r = KErrNotSupported;
+			return r;
+		}
+
+	RamAllocLock::Lock();
+
+	// Move the page to any RAM zone.
+	r = M::MovePage(aOld, aNew, KRamZoneInvalidId, EFalse);
+
+	RamAllocLock::Unlock();
+	return r;
+	}
+
+
+TInt M::MovePage(TPhysAddr aOld, TPhysAddr& aNew, TUint aBlockZoneId, TBool aBlockRest)
+	{
+	TInt r;
+
+	// get memory object corresponding to the page...
+	DMemoryObject* memory = 0;
+	MmuLock::Lock();
+	SPageInfo* pi = SPageInfo::SafeFromPhysAddr(aOld&~KPageMask);
+	if(pi)
+		{
+		if (pi->PagedState() != SPageInfo::EUnpaged)
+			{// The page is paged so let the pager handle it.
+			return ThePager.DiscardPage(pi, aBlockZoneId, aBlockRest);
+			}
+		if (pi->Type()==SPageInfo::EManaged)
+			memory = pi->Owner();
+		}
+	MmuLock::Unlock();
+
+	// Note, whilst we hold the RamAllocLock the page can't change it's use
+	// and we can safely assume that it still belongs to the memory object
+	// at a fixed page index.
+	// Also, as memory objects can't be destroyed whilst they still own pages
+	// we can safely access this object without taking an explicit referernce,
+	// i.e. we don't need to Open() the memory object.
+	if (!pi)
+		{// page info for aOld not found so aOld is not a RAM page...
+		r = KErrArgument;
+		}
+	else if(!memory)
+		{
+		// page does not have a memory manager, so we can't move it...
+		r = KErrNotSupported;
+		}
+	else
+		{
+		// move page...
+		r = memory->iManager->MovePage(memory, pi, aNew, aBlockZoneId, aBlockRest);
+		}
+	return r;
+	}