kernel/eka/memmodel/epoc/flexible/mmu/mdefrag.cpp
changeset 0 a41df078684a
child 26 c734af59ce98
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     1 // Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of the License "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #include <memmodel.h>
       
    17 #include <ramalloc.h>
       
    18 #include "mm.h"
       
    19 #include "mmu.h"
       
    20 #include "mmanager.h"
       
    21 #include "mobject.h"
       
    22 #include "mpager.h"
       
    23 #include "mmapping.h"
       
    24 
       
    25 
       
    26 TInt M::RamDefragFault(TAny* /*aExceptionInfo*/)
       
    27 	{// Defag faults are handled by Mmu::HandlePageFault() on the flexible memory model.
       
    28 	return KErrAbort;
       
    29 	} 
       
    30 
       
    31 
       
    32 EXPORT_C TInt Epoc::MovePhysicalPage(TPhysAddr aOld, TPhysAddr& aNew, TRamDefragPageToMove aPageToMove)
       
    33 	{
       
    34 	CHECK_PRECONDITIONS(MASK_THREAD_CRITICAL,"Epoc::MovePhysicalPage");
       
    35 	__KTRACE_OPT(KMMU,Kern::Printf("Epoc::MovePhysicalPage() old=%08x pageToMove=%d",aOld,aPageToMove));
       
    36 	// Mark aNew as invalid if a page is moved then this will be updated.
       
    37 	// However, if the page couldn't be moved or is discarded then it must be invalid.
       
    38 	aNew = KPhysAddrInvalid;
       
    39 
       
    40 	TInt r = KErrNotFound;
       
    41 
       
    42 	switch (aPageToMove)
       
    43 		{
       
    44 		case ERamDefragPage_Physical :
       
    45 			break;
       
    46 
       
    47 		case ERamDefragPage_PageTable :
       
    48 			{
       
    49 			// Assume aOld is a linear address in current thread and get the physical
       
    50 			// address of the page table that maps it and move that.
       
    51 			TLinAddr linAddr = (TLinAddr) aOld;
       
    52 			DMemModelThread* thread = (DMemModelThread*)TheCurrentThread;
       
    53 			// Get the os asid of current thread's process so no need to open reference on it.
       
    54 			TUint osAsid = ((DMemModelProcess*)thread->iOwningProcess)->OsAsid();
       
    55 			TUint offsetInMapping;
       
    56 			TUint mapInstanceCount;
       
    57 			DMemoryMapping* mapping = MM::FindMappingInAddressSpace(osAsid,linAddr,1,offsetInMapping,mapInstanceCount);
       
    58 			if (!mapping)
       
    59 				return r;
       
    60 			MmuLock::Lock();
       
    61 			TUint memoryIndex = (offsetInMapping >> KPageShift)+ mapping->iStartIndex;
       
    62 			TPte* pte = mapping->FindPageTable(linAddr, memoryIndex);
       
    63 			if (mapInstanceCount != mapping->MapInstanceCount() || !pte)
       
    64 				{
       
    65 				MmuLock::Unlock();
       
    66 				mapping->Close();
       
    67 				return r;
       
    68 				}
       
    69 			TPhysAddr physAddr = TheMmu.LinearToPhysical((TLinAddr)pte, KKernelOsAsid);
       
    70 			__NK_ASSERT_DEBUG(physAddr != KPhysAddrInvalid);
       
    71 			aOld = physAddr;	// Have physical address of page table page so move it.
       
    72 			MmuLock::Unlock();
       
    73 			mapping->Close();
       
    74 			break;
       
    75 			}
       
    76 
       
    77 		case ERamDefragPage_PageTableInfo :
       
    78 			{
       
    79 			// Assume aOld is a linear address in current thread and get physical 
       
    80 			// address of the page table info of the page table that maps it 
       
    81 			// and move that.
       
    82 			TLinAddr linAddr = (TLinAddr) aOld;
       
    83 			DMemModelThread* thread = (DMemModelThread*)TheCurrentThread;
       
    84 			// Get the os asid of current thread's process so no need to open reference on it.
       
    85 			TUint osAsid = ((DMemModelProcess*)thread->iOwningProcess)->OsAsid();
       
    86 			TUint offsetInMapping;
       
    87 			TUint mapInstanceCount;
       
    88 			DMemoryMapping* mapping = MM::FindMappingInAddressSpace(osAsid,linAddr,1,offsetInMapping,mapInstanceCount);
       
    89 			if (!mapping)
       
    90 				return r;
       
    91 			MmuLock::Lock();
       
    92 			TUint memoryIndex = (offsetInMapping >> KPageShift)+ mapping->iStartIndex;
       
    93 			TPte* pte = mapping->FindPageTable(linAddr, memoryIndex);
       
    94 			if (mapInstanceCount != mapping->MapInstanceCount() || !pte)
       
    95 				{
       
    96 				MmuLock::Unlock();
       
    97 				mapping->Close();
       
    98 				return r;
       
    99 				}
       
   100 			
       
   101 			SPageTableInfo* pti = SPageTableInfo::FromPtPtr(pte);
       
   102 			TPhysAddr physAddr = TheMmu.LinearToPhysical((TLinAddr)pti, KKernelOsAsid);
       
   103 			__NK_ASSERT_DEBUG(physAddr != KPhysAddrInvalid);
       
   104 			aOld = physAddr;	// Have physical address of page table info page so move it.
       
   105 			MmuLock::Unlock();
       
   106 			mapping->Close();
       
   107 			break;
       
   108 			}
       
   109 
       
   110 		default :
       
   111 			r = KErrNotSupported;
       
   112 			return r;
       
   113 		}
       
   114 
       
   115 	RamAllocLock::Lock();
       
   116 
       
   117 	// Move the page to any RAM zone.
       
   118 	r = M::MovePage(aOld, aNew, KRamZoneInvalidId, EFalse);
       
   119 
       
   120 	RamAllocLock::Unlock();
       
   121 	return r;
       
   122 	}
       
   123 
       
   124 
       
   125 TInt M::MovePage(TPhysAddr aOld, TPhysAddr& aNew, TUint aBlockZoneId, TBool aBlockRest)
       
   126 	{
       
   127 	TInt r;
       
   128 
       
   129 	// get memory object corresponding to the page...
       
   130 	DMemoryObject* memory = 0;
       
   131 	MmuLock::Lock();
       
   132 	SPageInfo* pi = SPageInfo::SafeFromPhysAddr(aOld&~KPageMask);
       
   133 	if(pi)
       
   134 		{
       
   135 		if (pi->PagedState() != SPageInfo::EUnpaged)
       
   136 			{// The page is paged so let the pager handle it.
       
   137 			return ThePager.DiscardPage(pi, aBlockZoneId, aBlockRest);
       
   138 			}
       
   139 		if (pi->Type()==SPageInfo::EManaged)
       
   140 			memory = pi->Owner();
       
   141 		}
       
   142 	MmuLock::Unlock();
       
   143 
       
   144 	// Note, whilst we hold the RamAllocLock the page can't change it's use
       
   145 	// and we can safely assume that it still belongs to the memory object
       
   146 	// at a fixed page index.
       
   147 	// Also, as memory objects can't be destroyed whilst they still own pages
       
   148 	// we can safely access this object without taking an explicit referernce,
       
   149 	// i.e. we don't need to Open() the memory object.
       
   150 	if (!pi)
       
   151 		{// page info for aOld not found so aOld is not a RAM page...
       
   152 		r = KErrArgument;
       
   153 		}
       
   154 	else if(!memory)
       
   155 		{
       
   156 		// page does not have a memory manager, so we can't move it...
       
   157 		r = KErrNotSupported;
       
   158 		}
       
   159 	else
       
   160 		{
       
   161 		// move page...
       
   162 		r = memory->iManager->MovePage(memory, pi, aNew, aBlockZoneId, aBlockRest);
       
   163 		}
       
   164 	return r;
       
   165 	}