kernel/eka/memmodel/epoc/multiple/mchunk.cpp
changeset 0 a41df078684a
child 26 c734af59ce98
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     1 // Copyright (c) 1994-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 // e32\memmodel\epoc\multiple\mchunk.cpp
       
    15 // 
       
    16 //
       
    17 
       
    18 #include "memmodel.h"
       
    19 #include "cache_maintenance.h"
       
    20 #include <mmubase.inl>
       
    21 #include <ramalloc.h>
       
    22 
       
    23 DMemModelChunk::DMemModelChunk()
       
    24 	{
       
    25 	}
       
    26 
       
    27 TLinearSection* DMemModelChunk::LinearSection()
       
    28 	{
       
    29 	Mmu& m=Mmu::Get();
       
    30 	TInt ar=(iAttributes&EAddressRangeMask);
       
    31 	switch (ar)
       
    32 		{
       
    33 		case EAddressLocal:			return ((DMemModelProcess*)iOwningProcess)->iLocalSection;
       
    34 		case EAddressFixed:			return NULL;
       
    35 		case EAddressShared:		return m.iSharedSection;
       
    36 		case EAddressUserGlobal:	return m.iUserGlobalSection;
       
    37 		case EAddressKernel:		return m.iKernelSection;
       
    38 		}
       
    39 	MM::Panic(MM::EChunkBadAddressRange);
       
    40 	return NULL;
       
    41 	}
       
    42 
       
    43 void DMemModelChunk::Destruct()
       
    44 	{
       
    45 	__KTRACE_OPT(KTHREAD,Kern::Printf("DMemModelChunk destruct %O",this));
       
    46 	if (iPageTables)
       
    47 		{
       
    48 #ifdef _DEBUG
       
    49 		TInt r;
       
    50 #define SET_R_IF_DEBUG(x)	r = (x)
       
    51 #else
       
    52 #define SET_R_IF_DEBUG(x)	(void)(x)
       
    53 #endif
       
    54 		if (iAttributes & EDisconnected)
       
    55 			SET_R_IF_DEBUG(Decommit(0,iMaxSize));
       
    56 		else if (iAttributes & EDoubleEnded)
       
    57 			SET_R_IF_DEBUG(AdjustDoubleEnded(0,0));
       
    58 		else
       
    59 			SET_R_IF_DEBUG(Adjust(0));
       
    60 		__ASSERT_DEBUG(r==KErrNone, MM::Panic(MM::EDecommitFailed));
       
    61 #ifdef _DEBUG
       
    62 		// check all page tables have been freed...
       
    63 		Mmu& m=Mmu::Get();
       
    64 		TInt nPdes=(iMaxSize+m.iChunkMask)>>m.iChunkShift;
       
    65 		for(TInt i=0; i<nPdes; i++)
       
    66 			{
       
    67 			__NK_ASSERT_DEBUG(iPageTables[i]==0xffff);
       
    68 			}
       
    69 #endif
       
    70 		}
       
    71 	if (iBase)
       
    72 		{
       
    73 		TLinearSection* s=LinearSection();
       
    74 		if(s)
       
    75 			{
       
    76 			Mmu::Wait();
       
    77 			__KTRACE_OPT(KMMU,Kern::Printf("DMemModelChunk::~DMemModelChunk remove region"));
       
    78 			Mmu& m=Mmu::Get();
       
    79 			s->iAllocator.Free( (TLinAddr(iBase)-s->iBase)>>m.iChunkShift, iMaxSize>>m.iChunkShift);
       
    80 			Mmu::Signal();
       
    81 			}
       
    82 		}
       
    83 	delete iOsAsids;
       
    84 	Kern::Free(iPageTables);
       
    85 	delete iPageBitMap;
       
    86 	delete iPermanentPageBitMap;
       
    87 
       
    88 	if(iKernelMirror)
       
    89 		iKernelMirror->Close(NULL);
       
    90 
       
    91 	TDfc* dfc = iDestroyedDfc;
       
    92 	if (dfc)
       
    93 		dfc->QueueOnIdle();
       
    94 
       
    95 	__KTRACE_OPT(KMEMTRACE, {Mmu::Wait(); Kern::Printf("MT:D %d %x %O",NTickCount(),this,this);Mmu::Signal();});
       
    96 #ifdef BTRACE_CHUNKS
       
    97 	BTraceContext4(BTrace::EChunks,BTrace::EChunkDestroyed,this);
       
    98 #endif
       
    99 	}
       
   100 
       
   101 TInt DMemModelChunk::Close(TAny* aPtr)
       
   102 	{
       
   103 	if (aPtr)
       
   104 		{
       
   105 		DMemModelProcess* pP=(DMemModelProcess*)aPtr;
       
   106 		if ((iAttributes&EMapTypeMask)==EMapTypeLocal)
       
   107 			pP=(DMemModelProcess*)iOwningProcess;
       
   108 		pP->RemoveChunk(this);
       
   109 		}
       
   110 	TInt r=Dec();
       
   111 	__KTRACE_OPT(KMMU,Kern::Printf("DMemModelChunk::Close %d %O",r,this));
       
   112 	__NK_ASSERT_DEBUG(r > 0); // Should never be negative.
       
   113 	if (r==1)
       
   114 		{
       
   115 		K::ObjDelete(this);
       
   116 		return EObjectDeleted;
       
   117 		}
       
   118 	return 0;
       
   119 	}
       
   120 
       
   121 
       
   122 TUint8* DMemModelChunk::Base(DProcess* aProcess)
       
   123 	{
       
   124 	return iBase;
       
   125 	}
       
   126 
       
   127 
       
   128 TInt DMemModelChunk::DoCreate(SChunkCreateInfo& aInfo)
       
   129 	{
       
   130 	__KTRACE_OPT(KMMU,Kern::Printf("Chunk %O DoCreate att=%08x",this,iAttributes));
       
   131 
       
   132 	__ASSERT_COMPILE(!(EMMChunkAttributesMask & EChunkAttributesMask));
       
   133 
       
   134 	if (aInfo.iMaxSize<=0)
       
   135 		return KErrArgument;
       
   136 
       
   137 	if (iKernelMirror)
       
   138 		{
       
   139 		iKernelMirror->iAttributes |= iAttributes|EMemoryNotOwned;
       
   140 		TInt r=iKernelMirror->DoCreate(aInfo);
       
   141 		if(r!=KErrNone)
       
   142 			return r;
       
   143 		}
       
   144 
       
   145 	Mmu& m=Mmu::Get();
       
   146 	TInt nPdes=(aInfo.iMaxSize+m.iChunkMask)>>m.iChunkShift;
       
   147 	iMaxSize=nPdes<<m.iChunkShift;
       
   148 	iMapAttr = aInfo.iMapAttr;
       
   149 	SetupPermissions();
       
   150 	TInt mapType=iAttributes & EMapTypeMask;
       
   151 	if (mapType==EMapTypeShared)
       
   152 		{
       
   153 		iOsAsids=TBitMapAllocator::New(m.iNumOsAsids,ETrue);
       
   154 		if (!iOsAsids)
       
   155 			return KErrNoMemory;
       
   156 		}
       
   157 	TInt maxpages=iMaxSize>>m.iPageShift;
       
   158 	if (iAttributes & EDisconnected)
       
   159 		{
       
   160 		TBitMapAllocator* pM=TBitMapAllocator::New(maxpages,ETrue);
       
   161 		if (!pM)
       
   162 			return KErrNoMemory;
       
   163 		iPageBitMap=pM;
       
   164 		__KTRACE_OPT(KMMU,Kern::Printf("PageBitMap at %08x, MaxPages %d",pM,maxpages));
       
   165 		}
       
   166 	if(iChunkType==ESharedKernelSingle || iChunkType==ESharedKernelMultiple)
       
   167 		{
       
   168 		TBitMapAllocator* pM=TBitMapAllocator::New(maxpages,ETrue);
       
   169 		if (!pM)
       
   170 			return KErrNoMemory;
       
   171 		iPermanentPageBitMap = pM;
       
   172 		}
       
   173 	iPageTables=(TUint16*)Kern::Alloc(nPdes*sizeof(TUint16));
       
   174 	if (!iPageTables)
       
   175 		return KErrNoMemory;
       
   176 	memset(iPageTables,0xff,nPdes*sizeof(TUint16));
       
   177 	MmuBase::Wait();
       
   178 	TInt r=AllocateAddress();
       
   179 	__KTRACE_OPT(KMEMTRACE,Kern::Printf("MT:C %d %x %O",NTickCount(),this,this));
       
   180 	MmuBase::Signal();
       
   181 #ifdef BTRACE_CHUNKS
       
   182 	TKName nameBuf;
       
   183 	Name(nameBuf);
       
   184 	BTraceContextN(BTrace::EChunks,BTrace::EChunkCreated,this,iMaxSize,nameBuf.Ptr(),nameBuf.Size());
       
   185 	if(iOwningProcess)
       
   186 		BTrace8(BTrace::EChunks,BTrace::EChunkOwner,this,iOwningProcess);
       
   187 	BTraceContext12(BTrace::EChunks,BTrace::EChunkInfo,this,iChunkType,iAttributes);
       
   188 #endif
       
   189 	return r;
       
   190 	}
       
   191 
       
   192 void DMemModelChunk::ClaimInitialPages()
       
   193 	{
       
   194 	__KTRACE_OPT(KMMU,Kern::Printf("Chunk %O ClaimInitialPages()",this));
       
   195 	Mmu& m=Mmu::Get();
       
   196 	TInt offset=0;
       
   197 	TUint32 ccp=K::CompressKHeapPtr(this);
       
   198 	NKern::LockSystem();
       
   199 	while(offset<iSize)
       
   200 		{
       
   201 		TInt ptid=m.PageTableId(TLinAddr(iBase)+offset);
       
   202 		__ASSERT_ALWAYS(ptid>=0,MM::Panic(MM::EClaimInitialPagesBadPageTable));
       
   203 		__KTRACE_OPT(KMMU,Kern::Printf("Offset %x PTID=%d",offset,ptid));
       
   204 		iPageTables[offset>>m.iChunkShift]=ptid;
       
   205 		SPageTableInfo& ptinfo = m.PtInfo(ptid);
       
   206 		ptinfo.SetChunk(ccp,offset>>m.iChunkShift);
       
   207 		TPte* pPte=(TPte*)m.PageTableLinAddr(ptid);
       
   208 		TInt i;
       
   209 		TInt np = 0;
       
   210 		TInt flashCount = MM::MaxPagesInOneGo;
       
   211 		for (i=0; i<m.iChunkSize>>m.iPageShift; ++i, offset+=m.iPageSize)
       
   212 			{
       
   213 			if(--flashCount<=0)
       
   214 				{
       
   215 				flashCount = MM::MaxPagesInOneGo;
       
   216 				NKern::FlashSystem();
       
   217 				}
       
   218 			TPte pte=pPte[i];
       
   219 			if (m.PteIsPresent(pte))
       
   220 				{
       
   221 				++np;
       
   222 				TPhysAddr phys=m.PtePhysAddr(pte, i);
       
   223 				__KTRACE_OPT(KMMU,Kern::Printf("Offset %x phys %08x",offset,phys));
       
   224 				SPageInfo* info = SPageInfo::SafeFromPhysAddr(phys);
       
   225 				if(info)
       
   226 					{
       
   227 					info->SetChunk(this,offset>>m.iPageShift);
       
   228 #ifdef BTRACE_KERNEL_MEMORY
       
   229 					--Epoc::KernelMiscPages; // page now owned by chunk, and is not 'miscelaneous'
       
   230 #endif
       
   231 					}
       
   232 				}
       
   233 			}
       
   234 		ptinfo.iCount = np;
       
   235 		__KTRACE_OPT(KMMU,Kern::Printf("Offset %x PTID %d NP %d", offset, ptid, np));
       
   236 		}
       
   237 	NKern::UnlockSystem();
       
   238 	}
       
   239 
       
   240 void DMemModelChunk::SetFixedAddress(TLinAddr aAddr, TInt aInitialSize)
       
   241 	{
       
   242 	__KTRACE_OPT(KMMU,Kern::Printf("DMemModelChunk %O SetFixedAddress %08x size %08x",this,aAddr,aInitialSize));
       
   243 	iBase=(TUint8*)aAddr;
       
   244 	iSize=Mmu::RoundToPageSize(aInitialSize);
       
   245 	ClaimInitialPages();
       
   246 	}
       
   247 
       
   248 TInt DMemModelChunk::Reserve(TInt aInitialSize)
       
   249 //
       
   250 // Reserve home section address space for a chunk
       
   251 //
       
   252 	{
       
   253 	__KTRACE_OPT(KMMU,Kern::Printf("DMemModelChunk %O Reserve() size %08x",this,aInitialSize));
       
   254 	iSize=Mmu::RoundToPageSize(aInitialSize);
       
   255 	ClaimInitialPages();
       
   256 	return KErrNone;
       
   257 	}
       
   258 
       
   259 TInt DMemModelChunk::Adjust(TInt aNewSize)
       
   260 //
       
   261 // Adjust a standard chunk.
       
   262 //
       
   263 	{
       
   264 
       
   265 	__KTRACE_OPT(KMMU,Kern::Printf("DMemModelChunk::Adjust %08x",aNewSize));
       
   266 	if (iAttributes & (EDoubleEnded|EDisconnected))
       
   267 		return KErrGeneral;
       
   268 	if (aNewSize<0 || aNewSize>iMaxSize)
       
   269 		return KErrArgument;
       
   270 
       
   271 	TInt r=KErrNone;
       
   272 	TInt newSize=Mmu::RoundToPageSize(aNewSize);
       
   273 	if (newSize!=iSize)
       
   274 		{
       
   275 		Mmu::Wait();
       
   276 		if (newSize>iSize)
       
   277 			{
       
   278 			__KTRACE_OPT(KMMU,Kern::Printf("DMemModelChunk::Adjust growing"));
       
   279 			r=DoCommit(iSize,newSize-iSize);
       
   280 			}
       
   281 		else if (newSize<iSize)
       
   282 			{
       
   283 			__KTRACE_OPT(KMMU,Kern::Printf("DMemModelChunk::Adjust shrinking"));
       
   284 			DoDecommit(newSize,iSize-newSize);
       
   285 			}
       
   286 		Mmu::Signal();
       
   287 		}
       
   288 	__COND_DEBUG_EVENT(r==KErrNone, EEventUpdateChunk, this);
       
   289 	__KTRACE_OPT(KMMU,Kern::Printf("DMemModelChunk %O adjusted to %x base %08x",this,iSize,iBase));
       
   290 	return r;
       
   291 	}
       
   292 
       
   293 TInt DMemModelChunk::Address(TInt aOffset, TInt aSize, TLinAddr& aKernelAddress)
       
   294 	{
       
   295 	if(!iPermanentPageBitMap)
       
   296 		return KErrAccessDenied;
       
   297 	if(TUint(aOffset)>=TUint(iMaxSize))
       
   298 		return KErrArgument;
       
   299 	if(TUint(aOffset+aSize)>TUint(iMaxSize))
       
   300 		return KErrArgument;
       
   301 	if(aSize<=0)
       
   302 		return KErrArgument;
       
   303 	TInt pageShift = Mmu::Get().iPageShift;
       
   304 	TInt start = aOffset>>pageShift;
       
   305 	TInt size = ((aOffset+aSize-1)>>pageShift)-start+1;
       
   306 	if(iPermanentPageBitMap->NotAllocated(start,size))
       
   307 		return KErrNotFound;
       
   308 	aKernelAddress = (TLinAddr)iKernelMirror->iBase+aOffset;
       
   309 	return KErrNone;
       
   310 	}
       
   311 
       
   312 TInt DMemModelChunk::PhysicalAddress(TInt aOffset, TInt aSize, TLinAddr& aKernelAddress, TUint32& aPhysicalAddress, TUint32* aPhysicalPageList)
       
   313 	{
       
   314 	TInt r=Address(aOffset,aSize,aKernelAddress);
       
   315 	if(r!=KErrNone)
       
   316 		return r;
       
   317 
       
   318 	return Mmu::Get().LinearToPhysical(aKernelAddress,aSize,aPhysicalAddress,aPhysicalPageList);
       
   319 	}
       
   320 
       
   321 void DMemModelChunk::Substitute(TInt aOffset, TPhysAddr aOldAddr, TPhysAddr aNewAddr)
       
   322 	{
       
   323 	// Substitute the page mapping at aOffset with aNewAddr.
       
   324 	// Enter and leave with system locked.
       
   325 	// This is sometimes called with interrupts disabled and should leave them alone.
       
   326 	Mmu& m = Mmu::Get();
       
   327 	__ASSERT_ALWAYS(iKernelMirror==NULL,MM::Panic(MM::EChunkRemapUnsupported));
       
   328 	
       
   329 	TInt ptid=iPageTables[aOffset>>m.iChunkShift];
       
   330 	if(ptid==0xffff)
       
   331 		MM::Panic(MM::EChunkRemapNoPageTable);
       
   332 
       
   333 	// Permissions for global code will have been overwritten with ApplyPermissions
       
   334 	// so we can't trust iPtePermissions for those chunk types
       
   335 	TPte perms;
       
   336    	if(iChunkType==EKernelCode)
       
   337 		perms = m.iKernelCodePtePerm;
       
   338 	else if(iChunkType==EDll)
       
   339 		perms = m.iGlobalCodePtePerm;
       
   340 	else
       
   341 		perms = iPtePermissions;
       
   342 
       
   343 	m.RemapPage(ptid, (TLinAddr)iBase+aOffset, aOldAddr, aNewAddr, perms, iOwningProcess);
       
   344 	}
       
   345 
       
   346 /**
       
   347 Get the movability type of the chunk's pages
       
   348 @return How movable the chunk's pages are
       
   349 */
       
   350 TZonePageType DMemModelChunk::GetPageType()
       
   351 	{
       
   352 	// Shared chunks have their physical addresses available
       
   353 	if (iChunkType == ESharedKernelSingle ||
       
   354 		iChunkType == ESharedKernelMultiple || 
       
   355 		iChunkType == ESharedIo ||
       
   356 		iChunkType == ESharedKernelMirror ||
       
   357 		iChunkType == EKernelMessage ||
       
   358 		iChunkType == EKernelData)	// Don't move kernel heap pages as DMA may be accessing them.
       
   359 		{
       
   360 		return EPageFixed;
       
   361 		}
       
   362 	// All other types of chunk are movable
       
   363 	return EPageMovable;
       
   364 	}
       
   365 
       
   366 TInt DMemModelChunk::DoCommit(TInt aOffset, TInt aSize, TCommitType aCommitType, TUint32* aExtraArg)
       
   367 	{
       
   368 	// Commit more RAM to a chunk at a specified offset
       
   369 	// enter and leave with system unlocked
       
   370 	// must hold RamAlloc mutex before calling this function
       
   371 	__ASSERT_MUTEX(MmuBase::RamAllocatorMutex);
       
   372 	__KTRACE_OPT(KMMU,Kern::Printf("DMemModelChunk::DoCommit %x+%x type=%d extra=%08x",aOffset,aSize,aCommitType,aExtraArg));
       
   373 	TInt offset=aOffset;
       
   374 	TInt endOffset=offset+aSize;
       
   375 	TInt newPtId=-1;
       
   376 	Mmu& m = Mmu::Get();
       
   377 	DRamAllocator& a = *m.iRamPageAllocator;
       
   378 	TInt r=KErrNone;
       
   379 	TPhysAddr pageList[KMaxPages];
       
   380 	TPhysAddr* pPageList=0; 	// In case of discontiguous commit it points to the list of physical pages.
       
   381 	TPhysAddr nextPage=0; 		// In case of contiguous commit, it points to the physical address to commit
       
   382 	SPageInfo::TType type = SPageInfo::EChunk;
       
   383 
       
   384 	// Set flag to indicate if RAM should be cleared before being committed.
       
   385 	// Note, EDll, EUserCode are covered in the code segment, in order not to clear
       
   386 	// the region overwritten by the loader
       
   387 	TBool clearRam =	iChunkType==EUserData
       
   388 					 || iChunkType==EDllData
       
   389 					 || iChunkType==EUserSelfModCode
       
   390 					 || iChunkType==ESharedKernelSingle
       
   391 					 || iChunkType==ESharedKernelMultiple
       
   392 					 || iChunkType==ESharedIo
       
   393 					 || iChunkType==ERamDrive;
       
   394 
       
   395 
       
   396 	TBool ownsMemory = !(iAttributes&EMemoryNotOwned);
       
   397 	TBool physicalCommit = aCommitType&DChunk::ECommitPhysicalMask;
       
   398 	if(ownsMemory)
       
   399 		{
       
   400 		if(physicalCommit)
       
   401 			return KErrNotSupported;
       
   402 		}
       
   403 	else
       
   404 		{
       
   405 		if(!physicalCommit && aCommitType != DChunk::ECommitVirtual)
       
   406 			return KErrNotSupported;
       
   407 		type = SPageInfo::EInvalid;	// to indicate page info not to be updated
       
   408 		}
       
   409 
       
   410 	switch(aCommitType)
       
   411 		{
       
   412 	case DChunk::ECommitDiscontiguous:
       
   413 		// No setup to do
       
   414 		break;
       
   415 
       
   416 	case DChunk::ECommitContiguous:
       
   417 		{
       
   418 		// Allocate a block of contiguous RAM from the free pool
       
   419 		TInt numPages=(endOffset-offset)>>m.iPageShift;
       
   420 		r=m.AllocContiguousRam(numPages<<m.iPageShift, nextPage, GetPageType(), 0);
       
   421 		if (r!=KErrNone)
       
   422 			return r;
       
   423 		if(clearRam)
       
   424 			m.ClearPages(numPages, (TPhysAddr*)(nextPage|1), iClearByte);  // clear RAM if required
       
   425 		*aExtraArg = nextPage;	// store physical address of RAM as return argument
       
   426 		}
       
   427 		break;
       
   428 
       
   429 	case DChunk::ECommitDiscontiguousPhysical:
       
   430 		{
       
   431 		pPageList = aExtraArg;				// use pages given given to us
       
   432 
       
   433 		// Check address of pages are multiples of page size...
       
   434 		TInt numPages=(endOffset-offset)>>m.iPageShift;
       
   435 		TUint32* ptr = aExtraArg;
       
   436 		TUint32* endPtr = aExtraArg+numPages;
       
   437 		if(ptr>=endPtr)
       
   438 			return KErrNone;				// Zero size commit is OK
       
   439 		TPhysAddr pageBits = 0;
       
   440 		do
       
   441 			pageBits |= *ptr++;
       
   442 		while(ptr<endPtr);
       
   443 		if(pageBits&(m.iPageSize-1))
       
   444 			return KErrArgument;			// all addresses must be multiple of page size
       
   445 		}
       
   446 		break;
       
   447 
       
   448 	case DChunk::ECommitContiguousPhysical:
       
   449 		nextPage = (TPhysAddr)aExtraArg;	// we have been given the physical address to use
       
   450 		if(nextPage&(m.iPageSize-1))
       
   451 			return KErrArgument;			// address must be multiple of page size
       
   452 		break;
       
   453 
       
   454 	case DChunk::ECommitVirtual:
       
   455 #ifndef __MARM__
       
   456 		return KErrNotSupported;
       
   457 #endif
       
   458 		break;
       
   459 
       
   460 	default:
       
   461 		return KErrNotSupported;
       
   462 		}
       
   463 
       
   464 	while(offset<endOffset)
       
   465 		{
       
   466 		TInt np=(endOffset-offset)>>m.iPageShift;	// pages remaining to satisfy request
       
   467 		TInt npEnd=(m.iChunkSize-(offset&m.iChunkMask))>>m.iPageShift;// number of pages to end of page table
       
   468 		if (np>npEnd)
       
   469 			np=npEnd;								// limit to single page table
       
   470 		if (np>MM::MaxPagesInOneGo)
       
   471 			np=MM::MaxPagesInOneGo;					// limit
       
   472 		TInt ptid=iPageTables[offset>>m.iChunkShift];
       
   473 		newPtId=-1;
       
   474 		if (ptid==0xffff)
       
   475 			{
       
   476 			// need to allocate a new page table
       
   477 			newPtId=m.AllocPageTable();
       
   478 			if (newPtId<0)
       
   479 				{
       
   480 				r=KErrNoMemory;
       
   481 				break;	// Exit the loop. Below, we'll free all ram
       
   482 						// that is allocated in the previous loop passes.
       
   483 				}
       
   484 			ptid=newPtId;
       
   485 			}
       
   486 
       
   487 		if(aCommitType==DChunk::ECommitDiscontiguous)
       
   488 			{
       
   489 			pPageList = pageList;
       
   490 			r=m.AllocRamPages(pPageList,np, GetPageType());	// try to allocate pages
       
   491 			if (r!=KErrNone)  //If fail, clean up what was allocated in this loop.
       
   492 				{
       
   493 				if (newPtId>=0)
       
   494 					m.FreePageTable(newPtId);
       
   495 					break;	// Exit the loop. Below, we'll free all ram
       
   496 							// that is allocated in the previous loop passes.
       
   497 				}
       
   498 			if(clearRam)
       
   499 				m.ClearPages(np, pPageList, iClearByte);	// clear RAM if required
       
   500 			}
       
   501 
       
   502 		TInt commitSize = np<<m.iPageShift;
       
   503 		
       
   504 
       
   505 		// In shared chunks (visible to both user and kernel side), it is always kernel side
       
   506 		// to be mapped the first. Decommiting will go in reverse order.
       
   507 		if(iKernelMirror)
       
   508 			{
       
   509 			// Map the same memory into the kernel mirror chunk
       
   510 			if(pPageList)
       
   511 				r = iKernelMirror->DoCommit(offset,commitSize,ECommitDiscontiguousPhysical,pPageList);
       
   512 			else
       
   513 				r = iKernelMirror->DoCommit(offset,commitSize,ECommitContiguousPhysical,(TUint32*)nextPage);
       
   514 			__KTRACE_OPT(KMMU,Kern::Printf("iKernelMirror->DoCommit returns %d",r));
       
   515 			if(r!=KErrNone) //If fail, clean up what was allocated in this loop.
       
   516 				{
       
   517 				if(aCommitType==DChunk::ECommitDiscontiguous)
       
   518 					m.FreePages(pPageList,np,EPageFixed);
       
   519 				if (newPtId>=0)
       
   520 					m.FreePageTable(newPtId);
       
   521 				
       
   522 				break;	// Exit the loop. Below, we'll free all ram
       
   523 						// that is allocated in the previous loop passes.
       
   524 				}
       
   525 			}
       
   526 
       
   527 		// Commit the memory.
       
   528 		NKern::LockSystem(); // lock the system while we change the MMU mappings
       
   529 		iSize += commitSize;					// update committed size
       
   530 		if (aCommitType==DChunk::ECommitVirtual)
       
   531 			m.MapVirtual(ptid, np);
       
   532 		else if(pPageList)
       
   533 			{
       
   534 			m.MapRamPages(ptid, type, this, offset, pPageList, np, iPtePermissions);
       
   535 			pPageList += np;
       
   536 			}
       
   537 		else
       
   538 			{
       
   539 			m.MapPhysicalPages(ptid, type, this, offset, nextPage, np, iPtePermissions);
       
   540 			nextPage += commitSize;
       
   541 			}
       
   542 		NKern::UnlockSystem();
       
   543 
       
   544 		if (newPtId>=0)
       
   545 			{
       
   546 			// We have allocated a new page table, now we must assign it
       
   547 			iPageTables[offset>>m.iChunkShift]=ptid;
       
   548 			TLinAddr addr=(TLinAddr)iBase+offset;	// current address
       
   549 			m.AssignPageTable(ptid, SPageTableInfo::EChunk, this, addr, iPdePermissions);
       
   550 			newPtId = -1;
       
   551 			}
       
   552 		__KTRACE_OPT(KMEMTRACE,Kern::Printf("MT:A %d %x %x %O",NTickCount(),this,iSize,this));
       
   553 #ifdef BTRACE_CHUNKS
       
   554 		BTraceContext12(BTrace::EChunks,ownsMemory?BTrace::EChunkMemoryAllocated:BTrace::EChunkMemoryAdded,this,offset,commitSize);
       
   555 #endif
       
   556 		
       
   557 		offset += commitSize;				// update offset
       
   558 		}
       
   559 
       
   560 	if (r==KErrNone)
       
   561 		{
       
   562 		if(iPermanentPageBitMap)
       
   563 			iPermanentPageBitMap->Alloc(aOffset>>m.iPageShift,aSize>>m.iPageShift);
       
   564 		}
       
   565 	else
       
   566 		{
       
   567 		// We ran out of memory somewhere.
       
   568 		// Free any memory we succeeded in allocating in the loops before the one that failed
       
   569 		if (iChunkType != ESharedKernelMirror) //Kernel mirror chunk will be decommited alongside the main chunk.
       
   570 			{
       
   571 			DChunk::TDecommitType decommitType = aCommitType==DChunk::ECommitVirtual ?
       
   572 																DChunk::EDecommitVirtual : DChunk::EDecommitNormal;
       
   573 			DoDecommit(aOffset,offset-aOffset,decommitType);
       
   574 			}
       
   575 
       
   576 		if(aCommitType==DChunk::ECommitContiguous)
       
   577 			{
       
   578 			// Free the pages we allocated but didn't get around to commiting
       
   579 			// It has to go page after page as we cannot use FreePhysicalRam here because the part of
       
   580 			// of original allocated contiguous memory is already partly freed (in DoDecommit).
       
   581 			TPhysAddr last = nextPage + ((endOffset-offset)>>m.iPageShift<<m.iPageShift);
       
   582 			while(nextPage<last)
       
   583 				{
       
   584 				a.FreeRamPage(nextPage, GetPageType());
       
   585 				nextPage += m.iPageSize;
       
   586 				}
       
   587 			*aExtraArg = KPhysAddrInvalid;	// return invalid physical address
       
   588 			}
       
   589 
       
   590 		m.iAllocFailed=ETrue;
       
   591 		}
       
   592 	return r;
       
   593 	}
       
   594 
       
   595 void DMemModelChunk::DoDecommit(TInt aOffset, TInt aSize, TDecommitType aDecommitType)
       
   596 	{
       
   597 	// Decommit RAM from a chunk at a specified offset
       
   598 	// enter and leave with system unlocked
       
   599 	// must hold RamAlloc mutex before calling this function
       
   600 	__KTRACE_OPT(KMMU,Kern::Printf("DMemModelChunk::DoDecommit %x+%x",aOffset,aSize));
       
   601 	
       
   602 	TBool ownsMemory = !(iAttributes&EMemoryNotOwned);
       
   603 
       
   604 	TInt deferred=0;
       
   605 	TInt offset=aOffset;
       
   606 	TInt endOffset=offset+aSize;
       
   607 	Mmu& m = Mmu::Get();
       
   608 	DRamAllocator& a = *m.iRamPageAllocator;
       
   609 	TPhysAddr pageList[KMaxPages];
       
   610 	TLinAddr linearPageList[KMaxPages];
       
   611 	const TAny* asids=GLOBAL_MAPPING;
       
   612 	if (iOsAsids)
       
   613 		asids=iOsAsids;
       
   614 	else if (iOwningProcess)
       
   615 		asids=(const TAny*)((DMemModelProcess*)iOwningProcess)->iOsAsid;
       
   616 	TUint size_in_pages = (TUint)(Min(aSize,iSize)>>m.iPageShift);
       
   617 	TBool sync_decommit = (size_in_pages<m.iDecommitThreshold);
       
   618 	TInt total_freed=0;
       
   619 	while(offset<endOffset)
       
   620 		{
       
   621 		TInt np=(endOffset-offset)>>m.iPageShift;		// number of pages remaining to decommit
       
   622 		TInt pdeEnd=(offset+m.iChunkSize)&~m.iChunkMask;
       
   623 		TInt npEnd=(pdeEnd-offset)>>m.iPageShift;		// number of pages to end of page table
       
   624 		if (np>npEnd)
       
   625 			np=npEnd;									// limit to single page table
       
   626 		if (np>MM::MaxPagesInOneGo)
       
   627 			np=MM::MaxPagesInOneGo;						// limit
       
   628 		TLinAddr addr=(TLinAddr)iBase+offset;			// current address
       
   629 		TInt ptid=iPageTables[offset>>m.iChunkShift];	// get page table ID if a page table is already assigned here
       
   630 		if (ptid!=0xffff)
       
   631 			{
       
   632 			TInt nPtes=0;
       
   633 			TInt nUnmapped=0;
       
   634 
       
   635 #ifdef BTRACE_CHUNKS
       
   636 			TUint oldFree = m.FreeRamInBytes();
       
   637 #endif
       
   638 			// Unmap the pages, clear the PTEs and place the physical addresses of the now-free RAM pages in
       
   639 			// pageList. Return nPtes=number of pages placed in list, remain=number of PTEs remaining in page table
       
   640 			// Bit 31 of return value is set if TLB flush may be incomplete
       
   641 			NKern::LockSystem();
       
   642 			TInt remain;
       
   643 			if (ownsMemory)
       
   644 				{
       
   645 				if (aDecommitType == EDecommitVirtual)
       
   646 					remain=m.UnmapVirtual(ptid,addr,np,pageList,ETrue,nPtes,nUnmapped,iOwningProcess);
       
   647 				else
       
   648 					remain=m.UnmapPages(ptid,addr,np,pageList,ETrue,nPtes,nUnmapped,iOwningProcess);
       
   649 				}
       
   650 			else
       
   651 				{
       
   652 				if (aDecommitType == EDecommitVirtual)
       
   653 					remain=m.UnmapUnownedVirtual(ptid,addr,np,pageList,linearPageList,nPtes,nUnmapped,iOwningProcess);
       
   654 				else
       
   655 					remain=m.UnmapUnownedPages(ptid,addr,np,pageList,linearPageList,nPtes,nUnmapped,iOwningProcess);
       
   656 				}
       
   657             TInt nFree = ownsMemory ? nUnmapped : 0; //The number of pages to free
       
   658 			deferred |= remain;
       
   659 			TInt decommitSize=nPtes<<m.iPageShift;
       
   660 			iSize-=decommitSize;                // reduce the committed size
       
   661 			NKern::UnlockSystem();
       
   662 
       
   663 			
       
   664 
       
   665 			__KTRACE_OPT(KMEMTRACE,Kern::Printf("MT:A %d %x %x %O",NTickCount(),this,iSize,this));
       
   666 #ifdef BTRACE_CHUNKS
       
   667 			TUint reclaimed = (oldFree-m.FreeRamInBytes())>>m.iPageShift; // number of 'unlocked' pages reclaimed from ram cache
       
   668 			if(nFree-reclaimed)
       
   669 				BTraceContext12(BTrace::EChunks,ownsMemory?BTrace::EChunkMemoryDeallocated:BTrace::EChunkMemoryRemoved,this,offset,(nFree-reclaimed)<<m.iPageShift);
       
   670 #endif
       
   671 
       
   672 			if (sync_decommit && (remain & KUnmapPagesTLBFlushDeferred))
       
   673 				{
       
   674 				// must ensure DTLB flushed before doing cache purge on decommit
       
   675 				m.GenericFlush(Mmu::EFlushDTLB);
       
   676 				}
       
   677 
       
   678 			// if page table is now completely empty, unassign it and update chunk PDE info
       
   679 			remain &= KUnmapPagesCountMask;
       
   680 			if (remain==0)
       
   681 				{
       
   682 				m.DoUnassignPageTable(addr, asids);
       
   683 				m.FreePageTable(ptid);
       
   684 				iPageTables[offset>>m.iChunkShift]=0xffff;
       
   685 				}
       
   686 
       
   687 			// Physical memory not owned by the chunk has to be preserved from cache memory.
       
   688 			if(!ownsMemory)
       
   689 				{
       
   690 				// If a chunk has Kernel mirror, it is sufficient to do it just once.
       
   691 				if (!iKernelMirror)
       
   692 					{
       
   693 					TInt i;
       
   694 					for (i=0;i<nUnmapped;i++)
       
   695 						m.CacheMaintenanceOnPreserve(pageList[i], KPageSize, linearPageList[i], iMapAttr);
       
   696 					}
       
   697 				}
       
   698 			else if (nFree)
       
   699 				{
       
   700 	            // We can now return the decommitted pages to the free page list and sort out caching.
       
   701 				total_freed+=nFree;
       
   702 				if (sync_decommit) //Purge cache if the size is below decommit threshold
       
   703 					m.CacheMaintenanceOnDecommit(pageList, nFree);
       
   704 				a.FreeRamPages(pageList,nFree, GetPageType());
       
   705 				}
       
   706 
       
   707 			offset+=(np<<m.iPageShift);
       
   708 			}
       
   709 		else
       
   710 			{
       
   711 			__KTRACE_OPT(KMMU,Kern::Printf("No page table at %08x",addr));
       
   712 			if ((iAttributes&EDisconnected)==0)
       
   713 				MM::Panic(MM::EChunkDecommitNoPageTable);
       
   714 			offset=pdeEnd;	// disconnected chunk - step on to next PDE
       
   715 			}
       
   716 		}
       
   717 	if (deferred & KUnmapPagesTLBFlushDeferred)
       
   718 		m.GenericFlush( (iAttributes&ECode) ? Mmu::EFlushDTLB|Mmu::EFlushITLB : Mmu::EFlushDTLB );
       
   719 	
       
   720 	if (total_freed && !sync_decommit) //Flash entire cache if the size exceeds decommit threshold
       
   721 		CacheMaintenance::SyncPhysicalCache_All();		//On ARMv6, this deals with both L1 & L2 cache
       
   722 
       
   723 	// Kernel mapped part of the chunk is removed at the end. At this point, no user side is mapped 
       
   724 	// which ensures that evicting data from cache will surely succeed.
       
   725 	if(iKernelMirror)
       
   726 		iKernelMirror->DoDecommit(aOffset,aSize);
       
   727 	}
       
   728 
       
   729 
       
   730 TInt DMemModelChunk::AdjustDoubleEnded(TInt aBottom, TInt aTop)
       
   731 //
       
   732 // Adjust a double-ended chunk.
       
   733 //
       
   734 	{
       
   735 
       
   736 	__KTRACE_OPT(KMMU,Kern::Printf("DMemModelChunk::AdjustDoubleEnded %x-%x",aBottom,aTop));
       
   737 	if ((iAttributes & (EDoubleEnded|EDisconnected))!=EDoubleEnded)
       
   738 		return KErrGeneral;
       
   739 	if (aTop<0 || aBottom<0 || aTop<aBottom || aTop>iMaxSize)
       
   740 		return KErrArgument;
       
   741 	Mmu& m = Mmu::Get();
       
   742 	aBottom &= ~m.iPageMask;
       
   743 	aTop=(aTop+m.iPageMask)&~m.iPageMask;
       
   744 	TInt newSize=aTop-aBottom;
       
   745 	if (newSize>iMaxSize)
       
   746 		return KErrArgument;
       
   747 
       
   748 	Mmu::Wait();
       
   749 	TInt initBottom=iStartPos;
       
   750 	TInt initTop=iStartPos+iSize;
       
   751 	TInt nBottom=Max(aBottom,iStartPos);	// intersection bottom
       
   752 	TInt nTop=Min(aTop,iStartPos+iSize);	// intersection top
       
   753 	TInt r=KErrNone;
       
   754 	if (nBottom<nTop)
       
   755 		{
       
   756 		__KTRACE_OPT(KMMU,Kern::Printf("Initial and final regions intersect"));
       
   757 		if (initBottom<nBottom)
       
   758 			{
       
   759 			iStartPos=aBottom;
       
   760 			DoDecommit(initBottom,nBottom-initBottom);
       
   761 			}
       
   762 		if (initTop>nTop)
       
   763 			DoDecommit(nTop,initTop-nTop);	// this changes iSize
       
   764 		if (aBottom<nBottom)
       
   765 			{
       
   766 			r=DoCommit(aBottom,nBottom-aBottom);
       
   767 			if (r==KErrNone)
       
   768 				{
       
   769 				if (aTop>nTop)
       
   770 					r=DoCommit(nTop,aTop-nTop);
       
   771 				if (r==KErrNone)
       
   772 					iStartPos=aBottom;
       
   773 				else
       
   774 					DoDecommit(aBottom,nBottom-aBottom);
       
   775 				}
       
   776 			}
       
   777 		else if (aTop>nTop)
       
   778 			r=DoCommit(nTop,aTop-nTop);
       
   779 		}
       
   780 	else
       
   781 		{
       
   782 		__KTRACE_OPT(KMMU,Kern::Printf("Initial and final regions disjoint"));
       
   783 		if (iSize)
       
   784 			DoDecommit(initBottom,iSize);
       
   785 		iStartPos=aBottom;
       
   786 		if (newSize)
       
   787 			r=DoCommit(iStartPos,newSize);
       
   788 		}
       
   789 	Mmu::Signal();
       
   790 	__COND_DEBUG_EVENT(r==KErrNone, EEventUpdateChunk, this);
       
   791 	__KTRACE_OPT(KMMU,Kern::Printf("DMemModelChunk %O adjusted to %x+%x base %08x",this,iStartPos,iSize,iBase));
       
   792 	return r;
       
   793 	}
       
   794 
       
   795 TInt DMemModelChunk::Commit(TInt aOffset, TInt aSize, TCommitType aCommitType, TUint32* aExtraArg)
       
   796 //
       
   797 // Commit to a disconnected chunk.
       
   798 //
       
   799 	{
       
   800 	__KTRACE_OPT(KMMU,Kern::Printf("DMemModelChunk::Commit %x+%x type=%d extra=%08x",aOffset,aSize,aCommitType,aExtraArg));
       
   801 	if ((iAttributes & (EDoubleEnded|EDisconnected))!=EDisconnected)
       
   802 		return KErrGeneral;
       
   803 	if (aOffset<0 || aSize<0)
       
   804 		return KErrArgument;
       
   805 	if (aSize==0)
       
   806 		return KErrNone;
       
   807 	Mmu& m = Mmu::Get();
       
   808 	aSize+=(aOffset & m.iPageMask);
       
   809 	aOffset &= ~m.iPageMask;
       
   810 	aSize=(aSize+m.iPageMask)&~m.iPageMask;
       
   811 	if ((aOffset+aSize)>iMaxSize)
       
   812 		return KErrArgument;
       
   813 
       
   814 	Mmu::Wait();
       
   815 	TInt r=KErrNone;
       
   816 	TInt i=aOffset>>m.iPageShift;
       
   817 	TInt n=aSize>>m.iPageShift;
       
   818 	if (iPageBitMap->NotFree(i,n))
       
   819 		r=KErrAlreadyExists;
       
   820 	else
       
   821 		{
       
   822 		r=DoCommit(aOffset,aSize,aCommitType,aExtraArg);		
       
   823 		if (r==KErrNone)
       
   824 			iPageBitMap->Alloc(i,n);
       
   825 		}
       
   826 	Mmu::Signal();
       
   827 	__COND_DEBUG_EVENT(r==KErrNone, EEventUpdateChunk, this);
       
   828 	return r;
       
   829 	}
       
   830 
       
   831 TInt DMemModelChunk::Allocate(TInt aSize, TInt aGuard, TInt aAlign)
       
   832 //
       
   833 // Allocate offset and commit to a disconnected chunk.
       
   834 //
       
   835 	{
       
   836 	__KTRACE_OPT(KMMU,Kern::Printf("DMemModelChunk::Allocate %x %x %d",aSize,aGuard,aAlign));
       
   837 
       
   838 	// Only allow this to be called on disconnected chunks and not disconnected 
       
   839 	// cache chunks as when guards pages exist the bit map can't be used to determine
       
   840 	// the size of disconnected cache chunks as is required by Decommit().
       
   841 	if ((iAttributes & (EDoubleEnded|EDisconnected|ECache))!=EDisconnected)
       
   842 		return KErrGeneral;
       
   843 
       
   844 	if (aSize<=0 || aGuard<0)
       
   845 		return KErrArgument;
       
   846 	Mmu& m = Mmu::Get();
       
   847 	aAlign=Max(aAlign-m.iPageShift,0);
       
   848 	TInt base=TInt(TLinAddr(iBase)>>m.iPageShift);
       
   849 	aSize=(aSize+m.iPageMask)&~m.iPageMask;
       
   850 	aGuard=(aGuard+m.iPageMask)&~m.iPageMask;
       
   851 	if ((aSize+aGuard)>iMaxSize)
       
   852 		return KErrArgument;
       
   853 
       
   854 	Mmu::Wait();
       
   855 	TInt r=KErrNone;
       
   856 	TInt n=(aSize+aGuard)>>m.iPageShift;
       
   857 	TInt i=iPageBitMap->AllocAligned(n,aAlign,base,EFalse);		// allocate the offset
       
   858 	if (i<0)
       
   859 		r=KErrNoMemory;		// run out of reserved space for this chunk
       
   860 	else
       
   861 		{
       
   862 		TInt offset=i<<m.iPageShift;
       
   863 		__KTRACE_OPT(KMMU,Kern::Printf("Offset %x allocated",offset));
       
   864 		r=DoCommit(offset+aGuard,aSize);
       
   865 		if (r==KErrNone)
       
   866 			{
       
   867 			iPageBitMap->Alloc(i,n);
       
   868 			r=offset;		// if operation successful, return allocated offset
       
   869 			}
       
   870 		}
       
   871 	Mmu::Signal();
       
   872 	__KTRACE_OPT(KMMU,Kern::Printf("DMemModelChunk::Allocate returns %x",r));
       
   873 	__COND_DEBUG_EVENT(r==KErrNone, EEventUpdateChunk, this);
       
   874 	return r;
       
   875 	}
       
   876 
       
   877 TInt DMemModelChunk::Decommit(TInt aOffset, TInt aSize)
       
   878 //
       
   879 // Decommit from a disconnected chunk.
       
   880 //
       
   881 	{
       
   882 	return Decommit(aOffset, aSize, EDecommitNormal);
       
   883 	}
       
   884 
       
   885 TInt DMemModelChunk::Decommit(TInt aOffset, TInt aSize, TDecommitType aDecommitType)
       
   886 //
       
   887 // Decommit from a disconnected chunk
       
   888 // 
       
   889 // @param aDecommitType Used to indicate whether area was originally committed with the
       
   890 // 					  	ECommitVirtual type
       
   891 //
       
   892 	{
       
   893 	__KTRACE_OPT(KMMU,Kern::Printf("DMemModelChunk::Decommit %x+%x",aOffset,aSize));
       
   894 	if ((iAttributes & (EDoubleEnded|EDisconnected))!=EDisconnected)
       
   895 		return KErrGeneral;
       
   896 	if (aOffset<0 || aSize<0)
       
   897 		return KErrArgument;
       
   898 	if (aSize==0)
       
   899 		return KErrNone;
       
   900 #ifndef __MARM__
       
   901 	if (aDecommitType == EDecommitVirtual)
       
   902 		return KErrNotSupported;
       
   903 #endif
       
   904 	Mmu& m = Mmu::Get();
       
   905 	aSize+=(aOffset & m.iPageMask);
       
   906 	aOffset &= ~m.iPageMask;
       
   907 	aSize=(aSize+m.iPageMask)&~m.iPageMask;
       
   908 	if ((aOffset+aSize)>iMaxSize)
       
   909 		return KErrArgument;
       
   910 
       
   911 	Mmu::Wait();
       
   912 
       
   913 	// limit the range to the home region range
       
   914 	__KTRACE_OPT(KMMU,Kern::Printf("Rounded and Clipped range %x+%x",aOffset,aSize));
       
   915 
       
   916 	TInt i=aOffset>>m.iPageShift;
       
   917 	TInt n=aSize>>m.iPageShift;
       
   918 
       
   919 	__KTRACE_OPT(KMMU,Kern::Printf("Calling SelectiveFree(%d,%d)",i,n));
       
   920 	TUint oldAvail = iPageBitMap->iAvail;
       
   921 	TUint oldSize = iSize;
       
   922 
       
   923 	// Free those positions which are still commited and also any guard pages, 
       
   924 	// i.e. pages that are reserved in this chunk but which are not commited.
       
   925 	iPageBitMap->SelectiveFree(i,n);
       
   926 
       
   927 	DoDecommit(aOffset,aSize,aDecommitType);
       
   928 
       
   929 	if (iAttributes & ECache)
       
   930 		{// If this is the file server cache chunk then adjust the size based 
       
   931 		// on the bit map size because:-
       
   932 		//	- 	Unlocked and reclaimed pages will be unmapped without updating
       
   933 		// 		iSize or the bit map. 
       
   934 		//	-	DoDecommit() only decommits the mapped pages.
       
   935 		// For all other chunks what is mapped is what is committed to the 
       
   936 		// chunk so iSize is accurate.
       
   937 		TUint actualFreedPages = iPageBitMap->iAvail - oldAvail;
       
   938 		iSize = oldSize - (actualFreedPages << KPageShift);
       
   939 		}
       
   940 
       
   941 	Mmu::Signal();
       
   942 	__DEBUG_EVENT(EEventUpdateChunk, this);
       
   943 	return KErrNone;
       
   944 	}
       
   945 
       
   946 TInt DMemModelChunk::Unlock(TInt aOffset, TInt aSize)
       
   947 	{
       
   948 	__KTRACE_OPT(KMMU,Kern::Printf("DMemModelChunk::Unlock %x+%x",aOffset,aSize));
       
   949 	if (!(iAttributes&ECache))
       
   950 		return KErrGeneral;
       
   951 	if ((iAttributes & (EDoubleEnded|EDisconnected))!=EDisconnected)
       
   952 		return KErrGeneral;
       
   953 
       
   954 	// Mark this as the file server cache chunk.  This is safe as it is only the 
       
   955 	// file server that can invoke this function.
       
   956 	iAttributes |= ECache;
       
   957 
       
   958 	if (aOffset<0 || aSize<0)
       
   959 		return KErrArgument;
       
   960 	if (aSize==0)
       
   961 		return KErrNone;
       
   962 	Mmu& m = Mmu::Get();
       
   963 	aSize+=(aOffset & m.iPageMask);
       
   964 	aOffset &= ~m.iPageMask;
       
   965 	aSize=(aSize+m.iPageMask)&~m.iPageMask;
       
   966 	if ((aOffset+aSize)>iMaxSize)
       
   967 		return KErrArgument;
       
   968 
       
   969 	Mmu::Wait();
       
   970 	TInt r=KErrNone;
       
   971 	TInt i=aOffset>>m.iPageShift;
       
   972 	TInt n=aSize>>m.iPageShift;
       
   973 	if (iPageBitMap->NotAllocated(i,n))
       
   974 		r=KErrNotFound;
       
   975 	else
       
   976 		{
       
   977 #ifdef BTRACE_CHUNKS
       
   978 		TUint oldFree = m.FreeRamInBytes();
       
   979 #endif
       
   980 		r=m.UnlockRamCachePages((TLinAddr)(iBase+aOffset),n,iOwningProcess);
       
   981 #ifdef BTRACE_CHUNKS
       
   982 		if(r==KErrNone)
       
   983 			{
       
   984 			TUint unlocked = m.FreeRamInBytes()-oldFree; // size of memory unlocked
       
   985 			if(unlocked)
       
   986 				BTraceContext12(BTrace::EChunks,BTrace::EChunkMemoryDeallocated,this,aOffset,unlocked);
       
   987 			}
       
   988 #endif
       
   989 		}
       
   990 
       
   991 	Mmu::Signal();
       
   992 	__COND_DEBUG_EVENT(r==KErrNone, EEventUpdateChunk, this);
       
   993 	return r;
       
   994 	}
       
   995 
       
   996 TInt DMemModelChunk::Lock(TInt aOffset, TInt aSize)
       
   997 	{
       
   998 	__KTRACE_OPT(KMMU,Kern::Printf("DMemModelChunk::Lock %x+%x",aOffset,aSize));
       
   999 	if (!(iAttributes&ECache))
       
  1000 		return KErrGeneral;
       
  1001 	if ((iAttributes & (EDoubleEnded|EDisconnected))!=EDisconnected)
       
  1002 		return KErrGeneral;
       
  1003 	if (aOffset<0 || aSize<0)
       
  1004 		return KErrArgument;
       
  1005 	if (aSize==0)
       
  1006 		return KErrNone;
       
  1007 	Mmu& m = Mmu::Get();
       
  1008 	aSize+=(aOffset & m.iPageMask);
       
  1009 	aOffset &= ~m.iPageMask;
       
  1010 	aSize=(aSize+m.iPageMask)&~m.iPageMask;
       
  1011 	if ((aOffset+aSize)>iMaxSize)
       
  1012 		return KErrArgument;
       
  1013 
       
  1014 	Mmu::Wait();
       
  1015 	TInt r=KErrNone;
       
  1016 	TInt i=aOffset>>m.iPageShift;
       
  1017 	TInt n=aSize>>m.iPageShift;
       
  1018 	if (iPageBitMap->NotAllocated(i,n))
       
  1019 		r=KErrNotFound;
       
  1020 	else
       
  1021 		{
       
  1022 #ifdef BTRACE_CHUNKS
       
  1023 		TUint oldFree = m.FreeRamInBytes();
       
  1024 #endif
       
  1025 		r=m.LockRamCachePages((TLinAddr)(iBase+aOffset),n,iOwningProcess);
       
  1026 #ifdef BTRACE_CHUNKS
       
  1027 		if(r==KErrNone)
       
  1028 			{
       
  1029 			TUint locked = oldFree-m.FreeRamInBytes();
       
  1030 			if(locked)
       
  1031 				BTraceContext12(BTrace::EChunks,BTrace::EChunkMemoryAllocated,this,aOffset,locked);
       
  1032 			}
       
  1033 #endif
       
  1034 		}
       
  1035 	if(r!=KErrNone)
       
  1036 		{
       
  1037 		// decommit memory on error...
       
  1038 		__KTRACE_OPT(KMMU,Kern::Printf("Calling SelectiveFree(%d,%d)",i,n));
       
  1039 		TUint oldAvail = iPageBitMap->iAvail;
       
  1040 		iPageBitMap->SelectiveFree(i,n);	// free those positions which are actually allocated
       
  1041 		TUint oldSize = iSize;
       
  1042 
       
  1043 		DoDecommit(aOffset,aSize);
       
  1044 
       
  1045 		// Use the bit map to adjust the size of the chunk as unlocked and reclaimed pages
       
  1046 		// will have been unmapped but not removed from the bit map as DoDecommit() only 
       
  1047 		// decommits the mapped pages.
       
  1048 		TUint actualFreedPages = iPageBitMap->iAvail - oldAvail;
       
  1049 		iSize = oldSize - (actualFreedPages << KPageShift);
       
  1050 		}
       
  1051 
       
  1052 	Mmu::Signal();
       
  1053 	__COND_DEBUG_EVENT(r==KErrNone, EEventUpdateChunk, this);
       
  1054 	return r;
       
  1055 	}
       
  1056 
       
  1057 TInt DMemModelChunk::AllocateAddress()
       
  1058 	{
       
  1059 	__KTRACE_OPT(KMMU,Kern::Printf("Chunk %O AllocateAddress()",this));
       
  1060 	TLinearSection* s=LinearSection();
       
  1061 	if (!s)
       
  1062 		return KErrNone;				// chunk has fixed preallocated address
       
  1063 
       
  1064 	Mmu& m=Mmu::Get();
       
  1065 	TUint32 required=iMaxSize>>m.iChunkShift;
       
  1066 	__KTRACE_OPT(KMMU,Kern::Printf("Searching from low to high addresses"));
       
  1067 	TInt r=s->iAllocator.AllocConsecutive(required, EFalse);
       
  1068 	if (r<0)
       
  1069 		return KErrNoMemory;
       
  1070 	s->iAllocator.Alloc(r, required);
       
  1071 	iBase=(TUint8*)(s->iBase + (r<<m.iChunkShift));
       
  1072 	__KTRACE_OPT(KMMU,Kern::Printf("Address %08x allocated",iBase));
       
  1073 	return KErrNone;
       
  1074 	}
       
  1075 
       
  1076 void DMemModelChunk::ApplyPermissions(TInt aOffset, TInt aSize, TPte aPtePerm)
       
  1077 	{
       
  1078 	__KTRACE_OPT(KMMU,Kern::Printf("Chunk %O ApplyPermissions(%x+%x,%08x)",this,aOffset,aSize,aPtePerm));
       
  1079 	__ASSERT_ALWAYS(aOffset>=0 && aSize>=0, MM::Panic(MM::EChunkApplyPermissions1));
       
  1080 	if (aSize==0)
       
  1081 		return;
       
  1082 	Mmu& m=Mmu::Get();
       
  1083 	aOffset &= ~m.iPageMask;
       
  1084 	aSize=(aSize+m.iPageMask)&~m.iPageMask;
       
  1085 	TInt endOffset=aOffset+aSize;
       
  1086 	__ASSERT_ALWAYS(endOffset<=iMaxSize, MM::Panic(MM::EChunkApplyPermissions2));
       
  1087 
       
  1088 	Mmu::Wait();
       
  1089 	while(aOffset<endOffset)
       
  1090 		{
       
  1091 		TInt ptid=iPageTables[aOffset>>m.iChunkShift];
       
  1092 		TInt pdeEnd=(aOffset+m.iChunkSize)&~m.iChunkMask;
       
  1093 		if (ptid==0xffff)
       
  1094 			{
       
  1095 			aOffset=pdeEnd;
       
  1096 			continue;
       
  1097 			}
       
  1098 		TInt np=(endOffset-aOffset)>>m.iPageShift;		// number of pages remaining to process
       
  1099 		TInt npEnd=(pdeEnd-aOffset)>>m.iPageShift;		// number of pages to end of page table
       
  1100 		if (np>npEnd)
       
  1101 			np=npEnd;									// limit to single page table
       
  1102 		if (np>MM::MaxPagesInOneGo)
       
  1103 			np=MM::MaxPagesInOneGo;						// limit
       
  1104 		m.ApplyPagePermissions(ptid, (aOffset&m.iChunkMask)>>m.iPageShift, np, aPtePerm);
       
  1105 		aOffset+=(np<<m.iPageShift);
       
  1106 		}
       
  1107 	Mmu::Signal();
       
  1108 	}
       
  1109 
       
  1110 TInt DMemModelChunkHw::Close(TAny*)
       
  1111 	{
       
  1112 	__KTRACE_OPT(KOBJECT,Kern::Printf("DMemModelChunkHw::Close %d %O",AccessCount(),this));
       
  1113 	TInt r=Dec();
       
  1114 	if (r==1)
       
  1115 		{
       
  1116 		if (iLinAddr)
       
  1117 			{
       
  1118 			// Save data for cache maintenance before beind destroyed by DeallocateLinearAddress
       
  1119 			TPhysAddr pa = iPhysAddr;
       
  1120 			TLinAddr la = iLinAddr;
       
  1121 			TInt size = iSize;
       
  1122 			TUint attr = iAttribs;
       
  1123 			
       
  1124 			MmuBase& m=*MmuBase::TheMmu;
       
  1125 			MmuBase::Wait();
       
  1126 			m.Unmap(iLinAddr,iSize);
       
  1127 			MmuBase::Signal();
       
  1128 			DeallocateLinearAddress();
       
  1129 
       
  1130 			// Physical memory has to be evicted from cache(s).
       
  1131 			// Must be preserved as it can still be in use by the driver.
       
  1132 			MmuBase::Wait();
       
  1133 			m.CacheMaintenanceOnPreserve(pa, size ,la ,attr);
       
  1134 			MmuBase::Signal();
       
  1135 			}
       
  1136 		K::ObjDelete(this);
       
  1137 		}
       
  1138 	return r;
       
  1139 	}
       
  1140 
       
  1141 TInt DMemModelChunk::CheckAccess()
       
  1142 	{
       
  1143 	DProcess* pP=TheCurrentThread->iOwningProcess;
       
  1144 	if (iAttributes&EPrivate)
       
  1145 		{
       
  1146 		if (iOwningProcess && iOwningProcess!=pP && pP!=K::TheKernelProcess)
       
  1147 			return KErrAccessDenied;
       
  1148 		}
       
  1149 	return KErrNone;
       
  1150 	}
       
  1151 
       
  1152 
       
  1153 void DMemModelChunk::BTracePrime(TInt aCategory)
       
  1154 	{
       
  1155 	DChunk::BTracePrime(aCategory);
       
  1156 	
       
  1157 #ifdef BTRACE_CHUNKS
       
  1158 	if (aCategory == BTrace::EChunks || aCategory == -1)
       
  1159 		{
       
  1160 		MmuBase::Wait();
       
  1161 
       
  1162 		TBool memoryOwned = !(iAttributes&EMemoryNotOwned);
       
  1163 		MmuBase& m=*MmuBase::TheMmu;
       
  1164 		TInt committedBase = -1;
       
  1165 
       
  1166 		// look at each page table in this chunk...
       
  1167 		TUint chunkEndIndex = iMaxSize>>KChunkShift;
       
  1168 		for(TUint chunkIndex=0; chunkIndex<chunkEndIndex; ++chunkIndex)
       
  1169 			{
       
  1170 			TInt ptid = iPageTables[chunkIndex];
       
  1171 			if(ptid==0xffff)
       
  1172 				{
       
  1173 				// no page table...
       
  1174 				if(committedBase!=-1)
       
  1175 					{
       
  1176 					TUint committedEnd = chunkIndex*KChunkSize;
       
  1177 					BTrace12(BTrace::EChunks, memoryOwned?BTrace::EChunkMemoryAllocated:BTrace::EChunkMemoryAdded,this,committedBase,committedEnd-committedBase);
       
  1178 					committedBase = -1;
       
  1179 					}
       
  1180 				continue;
       
  1181 				}
       
  1182 
       
  1183 			TPte* pPte=(TPte*)m.PageTableLinAddr(ptid);
       
  1184 
       
  1185 			// look at each page in page table...
       
  1186 			NKern::LockSystem();
       
  1187 			for(TUint pageIndex=0; pageIndex<KChunkSize/KPageSize; ++pageIndex)
       
  1188 				{
       
  1189 				TBool committed = false;
       
  1190 				TPhysAddr phys = m.PtePhysAddr(pPte[pageIndex], pageIndex);
       
  1191 				if(phys!=KPhysAddrInvalid)
       
  1192 					{
       
  1193 					// we have a page...
       
  1194 					if(!memoryOwned)
       
  1195 						committed = true;
       
  1196 					else
       
  1197 						{
       
  1198 						// make sure we own the page...
       
  1199 						SPageInfo* pi = SPageInfo::SafeFromPhysAddr(phys);
       
  1200 						if(pi && pi->Type()==SPageInfo::EChunk && pi->Owner()==this)
       
  1201 							committed = true;
       
  1202 						}
       
  1203 					}
       
  1204 
       
  1205 				if(committed)
       
  1206 					{
       
  1207 					if(committedBase==-1)
       
  1208 						committedBase = chunkIndex*KChunkSize+pageIndex*KPageSize; // start of new region
       
  1209 					}
       
  1210 				else
       
  1211 					{
       
  1212 					if(committedBase!=-1)
       
  1213 						{
       
  1214 						// generate trace for region...
       
  1215 						NKern::FlashSystem();
       
  1216 						TUint committedEnd = chunkIndex*KChunkSize+pageIndex*KPageSize;
       
  1217 						BTrace12(BTrace::EChunks, memoryOwned?BTrace::EChunkMemoryAllocated:BTrace::EChunkMemoryAdded,this,committedBase,committedEnd-committedBase);
       
  1218 						committedBase = -1;
       
  1219 						}
       
  1220 					}
       
  1221 
       
  1222 				if((pageIndex&15)==0)
       
  1223 					NKern::FlashSystem();
       
  1224 				}
       
  1225 
       
  1226 			NKern::UnlockSystem();
       
  1227 			}
       
  1228 
       
  1229 		if(committedBase!=-1)
       
  1230 			{
       
  1231 			TUint committedEnd = chunkEndIndex*KChunkSize;
       
  1232 			BTrace12(BTrace::EChunks, memoryOwned?BTrace::EChunkMemoryAllocated:BTrace::EChunkMemoryAdded,this,committedBase,committedEnd-committedBase);
       
  1233 			}
       
  1234 
       
  1235 		MmuBase::Signal();
       
  1236 		}
       
  1237 #endif
       
  1238 	}