--- /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;
+ }