kernel/eka/memmodel/epoc/flexible/mmu/mpdalloc.cpp
changeset 0 a41df078684a
child 87 2f92ad2dc5db
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     1 // Copyright (c) 2007-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 "mm.h"
       
    18 #include "mmu.h"
       
    19 
       
    20 #include "mpdalloc.h"
       
    21 #include "mobject.h"
       
    22 #include "cache_maintenance.inl"
       
    23 
       
    24 
       
    25 // check enough space for page directories...
       
    26 __ASSERT_COMPILE(KNumOsAsids <= (KPageDirectoryEnd-KPageDirectoryBase)/KPageDirectorySize);
       
    27 
       
    28 
       
    29 PageDirectoryAllocator PageDirectories;
       
    30 
       
    31 
       
    32 const TUint KLocalPdShift = KPageDirectoryShift > KPageShift ? KPageDirectoryShift-1 : KPageShift;
       
    33 const TUint KLocalPdSize = 1<<KLocalPdShift;
       
    34 const TUint KLocalPdPages = 1<<(KLocalPdShift-KPageShift);
       
    35 
       
    36 
       
    37 __ASSERT_COMPILE((KPageDirectoryBase&(31*KPageDirectorySize))==0); // following code assumes this alignment
       
    38 
       
    39 void PageDirectoryAllocator::GlobalPdeChanged(TPde* aPde)
       
    40 	{
       
    41 	__NK_ASSERT_DEBUG(MmuLock::IsHeld());
       
    42 	__NK_ASSERT_DEBUG(TLinAddr(aPde)>=KPageDirectoryBase);
       
    43 	__NK_ASSERT_DEBUG(TLinAddr(aPde)<KPageDirectoryEnd);
       
    44 	__NK_ASSERT_DEBUG(KLocalPdSize==(TUint)KPageDirectorySize); // shouldn't be called if we have separate global PDs
       
    45 
       
    46 	TLinAddr addr = (TLinAddr(aPde)&KPageDirectoryMask)*(KChunkSize/sizeof(TPde));
       
    47 	if(addr<KGlobalMemoryBase)
       
    48 		return; // change was in local part of PD, so nothing to do
       
    49 	if(addr-KIPCAlias<KIPCAliasAreaSize)
       
    50 		return; // change was in IPC alias area, so nothing to do
       
    51 	if(!iAllocator)
       
    52 		return; // not yet initialised
       
    53 
       
    54 	TRACE2(("PageDirectoryAllocator::GlobalPdeChanged(0x%08x)",aPde));
       
    55 	TPde pde = *aPde;
       
    56 	TLinAddr pPde = KPageDirectoryBase+(TLinAddr(aPde)&KPageDirectoryMask); // first page directory
       
    57 
       
    58 	// copy PDE to all allocated page directories
       
    59 	pPde -= KPageDirectorySize; // start off at PD minus one
       
    60 	TLinAddr lastPd = KPageDirectoryBase+(KNumOsAsids-1)*KPageDirectorySize;
       
    61 	TUint32* ptr = iAllocator->iMap;
       
    62 	do
       
    63 		{
       
    64 		TUint32 bits = ~*ptr++;
       
    65 		do
       
    66 			{
       
    67 			pPde += KPageDirectorySize; // step to next page directory
       
    68 			if(bits&0x80000000u)
       
    69 				{
       
    70 				TRACE2(("!PDE %x=%x",pPde,pde));
       
    71 				*(TPde*)pPde = pde;
       
    72 				CacheMaintenance::SinglePdeUpdated(pPde);
       
    73 				}
       
    74 			}
       
    75 		while(bits<<=1);
       
    76 		pPde |= 31*KPageDirectorySize; // step to next group of 32 PDs
       
    77 		}
       
    78 	while(pPde<lastPd);
       
    79 	}
       
    80 
       
    81 
       
    82 void PageDirectoryAllocator::Init2()
       
    83 	{
       
    84 	TRACEB(("PageDirectoryAllocator::Init2()"));
       
    85 
       
    86 	// construct memory object for page directories...
       
    87 #if defined(__CPU_PAGE_TABLES_FULLY_CACHED)
       
    88 	TMemoryAttributes memAttr = EMemoryAttributeStandard;
       
    89 #else
       
    90 	TMemoryAttributes memAttr = (TMemoryAttributes)(EMemoryAttributeNormalUncached|EMemoryAttributeDefaultShareable);
       
    91 #endif
       
    92 	TInt r = MM::InitFixedKernelMemory(iPageDirectoryMemory, KPageDirectoryBase, KPageDirectoryEnd, KPageDirectorySize, EMemoryObjectHardware, EMemoryCreateNoWipe, memAttr, EMappingCreateFixedVirtual);
       
    93 	__NK_ASSERT_ALWAYS(r==KErrNone);
       
    94 
       
    95 	// initialise kernel page directory...
       
    96 	TPhysAddr kernelPd = Mmu::LinearToPhysical((TLinAddr)Mmu::PageDirectory(KKernelOsAsid));
       
    97 	iKernelPageDirectory = kernelPd;
       
    98 	((DMemModelProcess*)K::TheKernelProcess)->iPageDir = kernelPd;
       
    99 	AssignPages(KKernelOsAsid*(KPageDirectorySize>>KPageShift),KPageDirectorySize>>KPageShift,kernelPd);
       
   100 
       
   101 	// construct allocator...
       
   102 	iAllocator = TBitMapAllocator::New(KNumOsAsids,ETrue);
       
   103 	__NK_ASSERT_ALWAYS(iAllocator);
       
   104 	iAllocator->Alloc(KKernelOsAsid,1); // kernel page directory already allocated
       
   105 
       
   106 	TRACEB(("PageDirectoryAllocator::Init2 done"));
       
   107 	}
       
   108 
       
   109 
       
   110 void PageDirectoryAllocator::AssignPages(TUint aIndex, TUint aCount, TPhysAddr aPhysAddr)
       
   111 	{
       
   112 	__NK_ASSERT_DEBUG(aCount<=KMaxPageInfoUpdatesInOneGo);
       
   113 	MmuLock::Lock();
       
   114 	SPageInfo* pi = SPageInfo::FromPhysAddr(aPhysAddr);
       
   115 	SPageInfo* piEnd = pi+aCount;
       
   116 	while(pi<piEnd)
       
   117 		{
       
   118 		pi->SetPhysAlloc(iPageDirectoryMemory,aIndex);
       
   119 		++pi;
       
   120 		++aIndex;
       
   121 		}
       
   122 	MmuLock::Unlock();
       
   123 	}
       
   124 
       
   125 
       
   126 TInt PageDirectoryAllocator::Alloc(TUint aOsAsid, TPhysAddr& aPageDirectory)
       
   127 	{
       
   128 	TRACE(("PageDirectoryAllocator::Alloc(%d)",aOsAsid));
       
   129 
       
   130 	// get memory for local page directory...
       
   131 	Mmu& m = TheMmu;
       
   132 	TUint offset = aOsAsid*KPageDirectorySize;
       
   133 	TPhysAddr pdPhys;
       
   134 	RamAllocLock::Lock();
       
   135 	TInt r = m.AllocContiguousRam(pdPhys, KLocalPdPages, KLocalPdShift-KPageShift, iPageDirectoryMemory->RamAllocFlags());
       
   136 	if(r==KErrNone)
       
   137 		AssignPages(offset>>KPageShift,KLocalPdPages,pdPhys);
       
   138 	RamAllocLock::Unlock();
       
   139 
       
   140 	if(r==KErrNone)
       
   141 		{
       
   142 		TRACE(("PageDirectoryAllocator::Alloc pdPhys = 0x%08x",pdPhys));
       
   143 
       
   144 		// map local page directory...
       
   145 		r = MM::MemoryAddContiguous(iPageDirectoryMemory,MM::BytesToPages(offset),KLocalPdPages,pdPhys);
       
   146 		if(r!=KErrNone)
       
   147 			{
       
   148 			RamAllocLock::Lock();
       
   149 			m.FreeContiguousRam(pdPhys,KLocalPdPages);
       
   150 			RamAllocLock::Unlock();
       
   151 			}
       
   152 		else
       
   153 			{
       
   154 			aPageDirectory = pdPhys;
       
   155 
       
   156 			TPde* pd = Mmu::PageDirectory(aOsAsid);
       
   157 			const TUint globalOffset = (KGlobalMemoryBase>>KChunkShift)*sizeof(TPde); // start of global part
       
   158 
       
   159 			// clear local entries in page directory...
       
   160 			memclr(pd,globalOffset);
       
   161 			CacheMaintenance::PdesInitialised((TLinAddr)pd,globalOffset);
       
   162 
       
   163 			if(KLocalPdSize<(TUint)KPageDirectorySize)
       
   164 				{
       
   165 				// map global page directory after local part...
       
   166 				__NK_ASSERT_DEBUG(KLocalPdSize==globalOffset);
       
   167 				r = MM::MemoryAddContiguous(iPageDirectoryMemory, MM::BytesToPages(offset+KLocalPdSize), 
       
   168 						(KPageDirectorySize-KLocalPdSize)/KPageSize, iKernelPageDirectory+KLocalPdSize);
       
   169 				__NK_ASSERT_DEBUG(r==KErrNone); // can't fail
       
   170 				MmuLock::Lock(); // need lock because allocator not otherwise atomic
       
   171 				iAllocator->Alloc(aOsAsid,1);
       
   172 				MmuLock::Unlock();
       
   173 				}
       
   174 			else
       
   175 				{
       
   176 				// copy global entries to local page directory...
       
   177 				TPde* globalPd = Mmu::PageDirectory(KKernelOsAsid);
       
   178 				MmuLock::Lock(); // need lock because allocator not otherwise atomic, also  to make sure GlobalPdeChanged() only accesses extant PDs
       
   179 				memcpy((TUint8*)pd+globalOffset,(TUint8*)globalPd+globalOffset,KPageDirectorySize-globalOffset);
       
   180 				iAllocator->Alloc(aOsAsid,1);
       
   181 				MmuLock::Unlock();
       
   182 				CacheMaintenance::PdesInitialised((TLinAddr)((TUint8*)pd+globalOffset),KPageDirectorySize-globalOffset);
       
   183 				}
       
   184 			}
       
   185 		}
       
   186 	TRACE(("PageDirectoryAllocator::Alloc returns %d",r));
       
   187 	return r;
       
   188 	}
       
   189 
       
   190 
       
   191 void PageDirectoryAllocator::Free(TUint aOsAsid)
       
   192 	{
       
   193 	TRACE(("PageDirectoryAllocator::Free(%d)",aOsAsid));
       
   194 
       
   195 	MmuLock::Lock(); // need lock because allocator not otherwise atomic, also to make sure GlobalPdeChanged() only accesses extant PDs
       
   196 	iAllocator->Free(aOsAsid, 1);
       
   197 	MmuLock::Unlock();
       
   198 
       
   199 	const TUint KPageDirectoryPageCount = KPageDirectorySize>>KPageShift;
       
   200 	TPhysAddr pages[KPageDirectoryPageCount];
       
   201 	TUint n = MM::MemoryRemovePages(iPageDirectoryMemory,aOsAsid*KPageDirectoryPageCount,KPageDirectoryPageCount,pages);
       
   202 	(void)n;
       
   203 	__NK_ASSERT_DEBUG(n==KPageDirectoryPageCount);
       
   204 
       
   205 	RamAllocLock::Lock();
       
   206 	Mmu& m = TheMmu;
       
   207 	// Page directories are fixed.
       
   208 	m.FreeRam(pages, KLocalPdPages, EPageFixed);
       
   209 	RamAllocLock::Unlock();
       
   210 	}
       
   211