kerneltest/e32test/mmu/d_sharedchunk.cpp
changeset 0 a41df078684a
child 31 56f325a607ea
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     1 // Copyright (c) 2004-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 // e32test\mmu\d_sharedchunk.cpp
       
    15 // 
       
    16 //
       
    17 
       
    18 #include <kernel/kern_priv.h>
       
    19 #include <kernel/cache.h>
       
    20 #include "d_sharedchunk.h"
       
    21 
       
    22 TBool PhysicalCommitSupported = ETrue;
       
    23 
       
    24 #ifdef __EPOC32__
       
    25 #define TEST_PHYSICAL_COMMIT
       
    26 #endif
       
    27 
       
    28 static volatile TInt ChunkDestroyedCount=1;	// Test counter
       
    29 
       
    30 //
       
    31 // Class definitions
       
    32 //
       
    33 
       
    34 class DSharedChunkFactory : public DLogicalDevice
       
    35 	{
       
    36 public:
       
    37 	~DSharedChunkFactory();
       
    38 	virtual TInt Install();
       
    39 	virtual void GetCaps(TDes8& aDes) const;
       
    40 	virtual TInt Create(DLogicalChannelBase*& aChannel);
       
    41 	TInt ClaimMemory();
       
    42 	void ReleaseMemory();
       
    43 	TInt AllocMemory(TInt aSize, TUint32& aPhysAddr);
       
    44 	void FreeMemory(TInt aSize,TUint32 aPhysAddr);
       
    45 	void LockWait();
       
    46 	void LockSignal();
       
    47 private:
       
    48 	NFastMutex iLock;
       
    49 public:
       
    50 	TBool iMemoryInUse;
       
    51 	TUint32 iPhysBase;
       
    52 	TUint32 iPhysEnd;
       
    53 	TUint32 iPhysNext;
       
    54 	TInt* iDummyCell;
       
    55 	};
       
    56 
       
    57 class DSharedChunkChannel : public DLogicalChannelBase
       
    58 	{
       
    59 public:
       
    60 	DSharedChunkChannel();
       
    61 	~DSharedChunkChannel();
       
    62 	virtual TInt DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer);
       
    63 	virtual TInt Request(TInt aFunction, TAny* a1, TAny* a2);
       
    64 	DChunk* OpenChunk(TLinAddr* aKernelAddr=0, TInt* aMaxSize=0);
       
    65 	inline void LockWait()
       
    66 		{ iFactory->LockWait(); }
       
    67 	inline void LockSignal()
       
    68 		{ iFactory->LockSignal(); }
       
    69 	TUint32 DfcReadWrite(TUint32* aPtr, TUint32 aValue);
       
    70 	TUint32 IsrReadWrite(TUint32* aPtr, TUint32 aValue);
       
    71 public:
       
    72 	DSharedChunkFactory*	iFactory;
       
    73 	DChunk*					iChunk;
       
    74 	TLinAddr				iKernelAddress;
       
    75 	TInt					iMaxSize;
       
    76 	};
       
    77 
       
    78 class TChunkCleanup : public TDfc
       
    79 	{
       
    80 public:
       
    81 	TChunkCleanup(DSharedChunkFactory* aFactory,TBool aReleasePhysicalMemory);
       
    82 	~TChunkCleanup();
       
    83 	static void ChunkDestroyed(TChunkCleanup* aSelf);
       
    84 	void Cancel();
       
    85 public:
       
    86 	DSharedChunkFactory* iFactory;
       
    87 	TBool iReleasePhysicalMemory;
       
    88 	};
       
    89 
       
    90 //
       
    91 // TChunkCleanup
       
    92 //
       
    93 
       
    94 TChunkCleanup::TChunkCleanup(DSharedChunkFactory* aFactory,TBool aReleasePhysicalMemory)
       
    95 	: TDfc((TDfcFn)TChunkCleanup::ChunkDestroyed,this,Kern::SvMsgQue(),0)
       
    96 	, iFactory(0), iReleasePhysicalMemory(aReleasePhysicalMemory)
       
    97 	{
       
    98 	aFactory->Open();
       
    99 	iFactory = aFactory;
       
   100 	}
       
   101 
       
   102 TChunkCleanup::~TChunkCleanup()
       
   103 	{
       
   104 	if(iFactory)
       
   105 		iFactory->Close(0);
       
   106 	}
       
   107 
       
   108 void TChunkCleanup::ChunkDestroyed(TChunkCleanup* aSelf)
       
   109 	{
       
   110 	__KTRACE_OPT(KMMU,Kern::Printf("D_SHAREDCHUNK ChunkDestroyed DFC\n"));
       
   111 	DSharedChunkFactory* factory = aSelf->iFactory;
       
   112 	if(factory)
       
   113 		{
       
   114 		factory->LockWait();
       
   115 		if(aSelf->iReleasePhysicalMemory)
       
   116 			factory->ReleaseMemory();
       
   117 		factory->LockSignal();
       
   118 		__e32_atomic_add_ord32(&ChunkDestroyedCount, 1);
       
   119 		__KTRACE_OPT(KMMU,Kern::Printf("D_SHAREDCHUNK ChunkDestroyedCount=%d\n",ChunkDestroyedCount));
       
   120 		}
       
   121 	delete aSelf;
       
   122 	}
       
   123 
       
   124 void TChunkCleanup::Cancel()
       
   125 	{
       
   126 	if(iFactory)
       
   127 		{
       
   128 		iFactory->Close(0);
       
   129 		iFactory = 0;
       
   130 		}
       
   131 	};
       
   132 
       
   133 //
       
   134 // DSharedChunkFactory
       
   135 //
       
   136 
       
   137 TInt DSharedChunkFactory::Install()
       
   138 	{
       
   139 	TUint mm=Kern::HalFunction(EHalGroupKernel,EKernelHalMemModelInfo,0,0)&EMemModelTypeMask;
       
   140 	PhysicalCommitSupported = mm!=EMemModelTypeDirect && mm!=EMemModelTypeEmul;
       
   141 #ifdef __EPOC32__
       
   142 	if(PhysicalCommitSupported)
       
   143 		{
       
   144 		TInt physSize = 4096*1024;
       
   145 		TInt r=Epoc::AllocPhysicalRam(physSize, iPhysBase);
       
   146 		if(r!=KErrNone)
       
   147 			return r;
       
   148 		iPhysNext = iPhysBase;
       
   149 		iPhysEnd = iPhysBase+physSize;
       
   150 		iMemoryInUse = EFalse;
       
   151 		}
       
   152 #endif
       
   153 	// Make sure there is enough space on kernel heap to that heap doesn't need
       
   154 	// to expand when allocating objects. (Required for OOM and memory leak testing.)
       
   155 	TAny* expandHeap = Kern::Alloc(16*1024);
       
   156 	iDummyCell = new TInt;
       
   157 	Kern::Free(expandHeap);
       
   158 
       
   159 	return SetName(&KSharedChunkLddName);
       
   160 	}
       
   161 
       
   162 DSharedChunkFactory::~DSharedChunkFactory()
       
   163 	{
       
   164 #ifdef __EPOC32__
       
   165 	if(PhysicalCommitSupported)
       
   166 		Epoc::FreePhysicalRam(iPhysBase, iPhysEnd-iPhysBase);
       
   167 #endif
       
   168 	delete iDummyCell;
       
   169 	}
       
   170 
       
   171 void DSharedChunkFactory::GetCaps(TDes8& /*aDes*/) const
       
   172 	{
       
   173 	// Not used but required as DLogicalDevice::GetCaps is pure virtual
       
   174 	}
       
   175 
       
   176 TInt DSharedChunkFactory::Create(DLogicalChannelBase*& aChannel)
       
   177 	{
       
   178 	aChannel = NULL;
       
   179 	DSharedChunkChannel* channel=new DSharedChunkChannel;
       
   180 	if(!channel)
       
   181 		return KErrNoMemory;
       
   182 	channel->iFactory = this;
       
   183 	aChannel = channel;
       
   184 	return KErrNone;
       
   185 	}
       
   186 
       
   187 void DSharedChunkFactory::LockWait()
       
   188 	{
       
   189 	NKern::FMWait(&iLock);
       
   190 	}
       
   191 
       
   192 void DSharedChunkFactory::LockSignal()
       
   193 	{
       
   194 	NKern::FMSignal(&iLock);
       
   195 	}
       
   196 
       
   197 TInt DSharedChunkFactory::AllocMemory(TInt aSize, TUint32& aPhysAddr)
       
   198 	{
       
   199 	if(!PhysicalCommitSupported)
       
   200 		aSize = 0;
       
   201 	TInt r=KErrNone;
       
   202 	Kern::RoundToPageSize(aSize);
       
   203 	LockWait();
       
   204 	if(iPhysNext+aSize>iPhysEnd)
       
   205 		r = KErrNoMemory;
       
   206 	else
       
   207 		{
       
   208 		aPhysAddr = iPhysNext;
       
   209 		iPhysNext += aSize;
       
   210 		}
       
   211 	LockSignal();
       
   212 	return r;
       
   213 	}
       
   214 
       
   215 TInt DSharedChunkFactory::ClaimMemory()
       
   216 	{
       
   217 	if (__e32_atomic_swp_ord32(&iMemoryInUse, 1))
       
   218 		return KErrInUse;
       
   219 	iPhysNext = iPhysBase;	// reset allocation pointer
       
   220 	return KErrNone;
       
   221 	}
       
   222 
       
   223 void DSharedChunkFactory::ReleaseMemory()
       
   224 	{
       
   225 	iMemoryInUse=EFalse;
       
   226 	}
       
   227 
       
   228 void DSharedChunkFactory::FreeMemory(TInt aSize,TUint32 aPhysAddr)
       
   229 	{
       
   230 	if(!PhysicalCommitSupported)
       
   231 		aSize = 0;
       
   232 	if(iPhysNext!=aPhysAddr+aSize)
       
   233 		{ FAULT(); }	// Only support freeing from the end
       
   234 	Kern::RoundToPageSize(aSize);
       
   235 	LockWait();
       
   236 	iPhysNext -= aSize;
       
   237 	LockSignal();
       
   238 	}
       
   239 
       
   240 DECLARE_STANDARD_LDD()
       
   241 	{
       
   242 	return new DSharedChunkFactory;
       
   243 	}
       
   244 
       
   245 //
       
   246 // DSharedChunkChannel
       
   247 //
       
   248 
       
   249 TInt DSharedChunkChannel::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& /*aVer*/)
       
   250 	{
       
   251 	return KErrNone;
       
   252 	}
       
   253 
       
   254 DSharedChunkChannel::DSharedChunkChannel()
       
   255 	{
       
   256 	}
       
   257 
       
   258 DSharedChunkChannel::~DSharedChunkChannel()
       
   259 	{
       
   260 	if(iChunk)
       
   261 		iChunk->Close(0);
       
   262 	}
       
   263 
       
   264 
       
   265 void DoDfcReadWrite(TUint32* aArgs)
       
   266 	{
       
   267 	TUint32* ptr = (TUint32*)aArgs[0];
       
   268 	TUint32 value = aArgs[1];
       
   269 	aArgs[1] = *ptr;
       
   270 	*ptr = value;
       
   271 	NKern::FSSignal((NFastSemaphore*)aArgs[2]);
       
   272 	}
       
   273 
       
   274 TUint32 DSharedChunkChannel::DfcReadWrite(TUint32* aPtr, TUint32 aValue)
       
   275 	{
       
   276 	NFastSemaphore sem;
       
   277 	NKern::FSSetOwner(&sem,0);
       
   278 
       
   279 	TUint32 args[3];
       
   280 	args[0] = (TUint32)aPtr;
       
   281 	args[1] = aValue;
       
   282 	args[2] = (TUint32)&sem;
       
   283 
       
   284 	TDfc dfc((TDfcFn)DoDfcReadWrite,&args,Kern::SvMsgQue(),0);
       
   285 	dfc.Enque();
       
   286 	NKern::FSWait(&sem);
       
   287 
       
   288 	return args[1];
       
   289 	}
       
   290 
       
   291 
       
   292 void DoIsrReadWrite(TUint32* aArgs)
       
   293 	{
       
   294 	TUint32* ptr = (TUint32*)aArgs[0];
       
   295 	TUint32 value = aArgs[1];
       
   296 	aArgs[1] = *ptr;
       
   297 	*ptr = value;
       
   298 	((TDfc*)aArgs[2])->Add();
       
   299 	}
       
   300 
       
   301 void DoIsrReadWriteDfcCallback(TUint32* aArgs)
       
   302 	{
       
   303 	NKern::FSSignal((NFastSemaphore*)aArgs);
       
   304 	}
       
   305 
       
   306 TUint32 DSharedChunkChannel::IsrReadWrite(TUint32* aPtr, TUint32 aValue)
       
   307 	{
       
   308 	NFastSemaphore sem;
       
   309 	NKern::FSSetOwner(&sem,0);
       
   310 
       
   311 	TDfc dfc((TDfcFn)DoIsrReadWriteDfcCallback,&sem,Kern::SvMsgQue(),0);
       
   312 
       
   313 	TUint32 args[3];
       
   314 	args[0] = (TUint32)aPtr;
       
   315 	args[1] = aValue;
       
   316 	args[2] = (TUint32)&dfc;
       
   317 
       
   318 	NTimer timer((NTimerFn)DoIsrReadWrite,&args);
       
   319 	timer.OneShot(1);
       
   320 
       
   321 	NKern::FSWait(&sem);
       
   322 	return args[1];
       
   323 	}
       
   324 
       
   325 
       
   326 DChunk* DSharedChunkChannel::OpenChunk(TLinAddr* aKernelAddr,TInt* aMaxSize)
       
   327 	{
       
   328 	__ASSERT_CRITICAL	// Thread must be in critical section (to avoid leaking access count on chunk)
       
   329 	LockWait();
       
   330 	DChunk* chunk=iChunk;
       
   331 	if(chunk)
       
   332 		if(chunk->Open()!=KErrNone)
       
   333 			chunk = NULL;
       
   334 	if(aKernelAddr)
       
   335 		*aKernelAddr = chunk ? iKernelAddress : NULL;
       
   336 	if(aMaxSize)
       
   337 		*aMaxSize = chunk ? iMaxSize : 0;
       
   338 	LockSignal();
       
   339 	return chunk;
       
   340 	}
       
   341 
       
   342 
       
   343 TUint8 ReadByte(volatile TUint8* aPtr)
       
   344 	{
       
   345 	return *aPtr;
       
   346 	}
       
   347 
       
   348 void signal_sem(TAny* aPtr)
       
   349 	{
       
   350 	NKern::FSSignal((NFastSemaphore*)aPtr);
       
   351 	}
       
   352 
       
   353 TInt WaitForIdle()
       
   354 	{
       
   355 	NFastSemaphore s(0);
       
   356 	TDfc idler(&signal_sem, &s, Kern::SvMsgQue(), 0);	// supervisor thread, priority 0, so will run after destroyed DFC
       
   357 	NTimer timer(&signal_sem, &s);
       
   358 	idler.QueueOnIdle();
       
   359 	timer.OneShot(NKern::TimerTicks(5000), ETrue);	// runs in DFCThread1
       
   360 	NKern::FSWait(&s);	// wait for either idle DFC or timer
       
   361 	TBool timeout = idler.Cancel();	// cancel idler, return TRUE if it hadn't run
       
   362 	TBool tmc = timer.Cancel();	// cancel timer, return TRUE if it hadn't expired
       
   363 	if (!timeout && !tmc)
       
   364 		NKern::FSWait(&s);	// both the DFC and the timer went off - wait for the second one
       
   365 	if (timeout)
       
   366 		return KErrTimedOut;
       
   367 	return KErrNone;
       
   368 	}
       
   369 
       
   370 
       
   371 TInt WaitForIdle2()
       
   372 	{
       
   373 	TInt r = WaitForIdle(); // wait for chunk async delete
       
   374 	if(r==KErrNone)
       
   375 		r = WaitForIdle();	// wait for chunk destroyed notification DFC
       
   376 	return r;
       
   377 	}
       
   378 
       
   379 
       
   380 TInt DSharedChunkChannel::Request(TInt aFunction, TAny* a1, TAny* a2)
       
   381 	{
       
   382 	TInt i1 = (TInt)a1;
       
   383 	TInt i2 = (TInt)a2;
       
   384 
       
   385 	TInt r=KErrNotSupported;
       
   386 
       
   387 	switch(aFunction)
       
   388 		{
       
   389 
       
   390 	case RSharedChunkLdd::ECreateChunk:
       
   391 		{
       
   392 		NKern::ThreadEnterCS();
       
   393 		if (__e32_atomic_load_acq32(&ChunkDestroyedCount)==0)
       
   394 			{
       
   395 			WaitForIdle2(); // Go idle for a while to let chunk cleanup DFCs to be called
       
   396 			}
       
   397 
       
   398 		// Create cleanup item
       
   399 		TBool chunkUsesPhysicalMemory = (i1&EOwnsMemory)==0;
       
   400 
       
   401 		TChunkCleanup* cleanup = new TChunkCleanup(this->iFactory,chunkUsesPhysicalMemory);
       
   402 		if(!cleanup)
       
   403 			{
       
   404 			NKern::ThreadLeaveCS();
       
   405 			return KErrNoMemory;
       
   406 			}
       
   407 
       
   408 		// Try and create chunk...
       
   409 		DChunk* chunk;
       
   410 		TChunkCreateInfo info;
       
   411 
       
   412 		info.iType		 = (i1&EMultiple)
       
   413 							? TChunkCreateInfo::ESharedKernelMultiple
       
   414 							: TChunkCreateInfo::ESharedKernelSingle;
       
   415 
       
   416 		info.iMaxSize	 = i1&~ECreateFlagsMask;
       
   417 #ifdef __EPOC32__
       
   418 		info.iMapAttr	 = (i1&ECached) ? EMapAttrCachedMax
       
   419 						 : (i1&EBuffered) ? EMapAttrBufferedC
       
   420 						 : EMapAttrFullyBlocking;
       
   421 #endif
       
   422 		info.iOwnsMemory = (i1&EOwnsMemory)!=0;
       
   423 
       
   424 		info.iDestroyedDfc = cleanup;
       
   425 
       
   426 		if(i1&EBadType) *(TUint8*)&info.iType = 0xff;
       
   427 
       
   428 		TUint32 mapAttr;
       
   429 		TUint32 kernAddr;
       
   430 		r = Kern::ChunkCreate(info, chunk, kernAddr, mapAttr);
       
   431 		if(r!=KErrNone)
       
   432 			{
       
   433 			delete cleanup;
       
   434 			NKern::ThreadLeaveCS();
       
   435 			return r;
       
   436 			}
       
   437 
       
   438 		// Setup data members
       
   439 		LockWait();
       
   440 		if(iChunk)
       
   441 			r = KErrAlreadyExists;
       
   442 		else
       
   443 			{
       
   444 			if(chunkUsesPhysicalMemory)
       
   445 				r = iFactory->ClaimMemory();
       
   446 			if(r==KErrNone)
       
   447 				{
       
   448 				iChunk = chunk;
       
   449 				iKernelAddress = kernAddr;
       
   450 				iMaxSize = info.iMaxSize;
       
   451 				__e32_atomic_store_ord32(&ChunkDestroyedCount,0);
       
   452 				}
       
   453 			}
       
   454 		LockSignal();
       
   455 
       
   456 		if(r!=KErrNone)
       
   457 			{
       
   458 			// There was an error, so discard created chunk
       
   459 			cleanup->Cancel();
       
   460 			Kern::ChunkClose(chunk);
       
   461 			NKern::ThreadLeaveCS();
       
   462 			return r;
       
   463 			}
       
   464 
       
   465 		NKern::ThreadLeaveCS();
       
   466 
       
   467 		// Write back kernel address of chunk
       
   468 		if(a2)
       
   469 			kumemput32(a2,(TAny*)&kernAddr,4);
       
   470 
       
   471 		return KErrNone;
       
   472 		}
       
   473 
       
   474 
       
   475 	case RSharedChunkLdd::EGetChunkHandle:
       
   476 		{
       
   477 		NKern::ThreadEnterCS();
       
   478 		DChunk* chunk=OpenChunk();
       
   479 		if(chunk)
       
   480 			{
       
   481 			r = Kern::MakeHandleAndOpen(0,chunk);
       
   482 			chunk->Close(0);
       
   483 			}
       
   484 		else
       
   485 			r = KErrNotFound;
       
   486 		NKern::ThreadLeaveCS();
       
   487 		return r;
       
   488 		}
       
   489 
       
   490 
       
   491 	case RSharedChunkLdd::ECloseChunkHandle:
       
   492 		{
       
   493 		NKern::ThreadEnterCS();
       
   494 		r = Kern::CloseHandle(0,i1);
       
   495 		NKern::ThreadLeaveCS();
       
   496 		return r;
       
   497 		}
       
   498 
       
   499 
       
   500 	case RSharedChunkLdd::ECommitMemory:
       
   501 		{
       
   502 		NKern::ThreadEnterCS();
       
   503 		TUint32 chunkKernelAddress;
       
   504 		DChunk* chunk=OpenChunk(&chunkKernelAddress);
       
   505 		if(chunk)
       
   506 			{
       
   507 			TInt type = i1&ECommitTypeMask;
       
   508 			i1 &= ~ECommitTypeMask;
       
   509 			switch(type)
       
   510 				{
       
   511 			case EDiscontiguous:
       
   512 				r = Kern::ChunkCommit(chunk,i1,i2);
       
   513 				break;
       
   514 
       
   515 			case EContiguous:
       
   516 				{
       
   517 				TUint32 physAddr=~0u;
       
   518 				r = Kern::ChunkCommitContiguous(chunk,i1,i2,physAddr);
       
   519 				if(r!=KErrNone || i2==0)
       
   520 					break;
       
   521 				if(physAddr==~0u)
       
   522 					{ r=KErrGeneral; break; }
       
   523 
       
   524 				// Check that ChunkPhysicalAddress returns addresses consistant with the commit
       
   525 				TUint32 kernAddr;
       
   526 				TUint32 mapAttr;
       
   527 				TUint32 physAddr2;
       
   528 				r = Kern::ChunkPhysicalAddress(chunk, i1, i2, kernAddr, mapAttr, physAddr2);
       
   529 				if(r==KErrNone)
       
   530 					if(kernAddr!=chunkKernelAddress+i1 || physAddr2!=physAddr)
       
   531 						r=KErrGeneral;
       
   532 
       
   533 				if(r==KErrNone)
       
   534 					{
       
   535 					// Exercise memory sync functions
       
   536 					Cache::SyncMemoryBeforeDmaRead(kernAddr, i2, mapAttr);
       
   537 					Cache::SyncMemoryBeforeDmaWrite(kernAddr, i2, mapAttr);
       
   538 					}
       
   539 				}
       
   540 				break;
       
   541 
       
   542 			case EDiscontiguousPhysical|EBadPhysicalAddress:
       
   543 			case EDiscontiguousPhysical:
       
   544 				{
       
   545 				TUint32 physAddr;
       
   546 				r = iFactory->AllocMemory(i2,physAddr);
       
   547 				if(r!=KErrNone)
       
   548 					break;
       
   549 
       
   550 				TInt pageSize =	Kern::RoundToPageSize(1);
       
   551 				TInt numPages = Kern::RoundToPageSize(i2)/pageSize;
       
   552 				TUint32* physAddrList = new TUint32[numPages];
       
   553 				TInt i;
       
   554 				for(i=0; i<numPages; i++)
       
   555 					physAddrList[i] = physAddr+i*pageSize;
       
   556 				if(type&EBadPhysicalAddress)
       
   557 					physAddrList[i-1] |= 1;
       
   558 				r = Kern::ChunkCommitPhysical(chunk,i1,i2,physAddrList);
       
   559 				delete[] physAddrList;
       
   560 				if(r!=KErrNone || i2==0)
       
   561 					{
       
   562 					iFactory->FreeMemory(i2,physAddr);
       
   563 					break;
       
   564 					}
       
   565 
       
   566 				// Check that ChunkPhysicalAddress returns the same addresses we used in the commit
       
   567 				TUint32 kernAddr;
       
   568 				TUint32 mapAttr;
       
   569 				TUint32 physAddr2;
       
   570 				TUint32* physAddrList2 = new TUint32[numPages];
       
   571 				r = Kern::ChunkPhysicalAddress(chunk, i1, i2, kernAddr, mapAttr, physAddr2, physAddrList2);
       
   572 				if(r==KErrNone)
       
   573 					{
       
   574 					if(kernAddr!=chunkKernelAddress+i1 || physAddr2!=physAddr)
       
   575 						r=KErrGeneral;
       
   576 					else
       
   577 						for(i=0; i<numPages; i++)
       
   578 							if(physAddrList2[i] != physAddr+i*pageSize)
       
   579 								r = KErrGeneral;
       
   580 					}
       
   581 				delete[] physAddrList2;
       
   582 
       
   583 				if(r==KErrNone)
       
   584 					{
       
   585 					// Exercise memory sync functions
       
   586 					Cache::SyncMemoryBeforeDmaRead(kernAddr, i2, mapAttr);
       
   587 					Cache::SyncMemoryBeforeDmaWrite(kernAddr, i2, mapAttr);
       
   588 					}
       
   589 				}
       
   590 				break;
       
   591 
       
   592 			case EContiguousPhysical|EBadPhysicalAddress:
       
   593 			case EContiguousPhysical:
       
   594 				{
       
   595 				TUint32 physAddr;
       
   596 				r = iFactory->AllocMemory(i2,physAddr);
       
   597 				if(r==KErrNone)
       
   598 					{
       
   599 					if(type&EBadPhysicalAddress)
       
   600 						r = Kern::ChunkCommitPhysical(chunk,i1,i2,physAddr|1);
       
   601 					else
       
   602 						r = Kern::ChunkCommitPhysical(chunk,i1,i2,physAddr);
       
   603 					}
       
   604 				if(r!=KErrNone || i2==0)
       
   605 					{
       
   606 					iFactory->FreeMemory(i2,physAddr);
       
   607 					break;
       
   608 					}
       
   609 
       
   610 				// Check that ChunkPhysicalAddress returns the same addresses we used in the commit
       
   611 				TUint32 kernAddr;
       
   612 				TUint32 mapAttr;
       
   613 				TUint32 physAddr2;
       
   614 				r = Kern::ChunkPhysicalAddress(chunk, i1, i2, kernAddr, mapAttr, physAddr2);
       
   615 				if(r==KErrNone)
       
   616 					if(kernAddr!=chunkKernelAddress+i1 || physAddr2!=physAddr)
       
   617 						r=KErrGeneral;
       
   618 
       
   619 				if(r==KErrNone)
       
   620 					{
       
   621 					// Exercise memory sync functions
       
   622 					Cache::SyncMemoryBeforeDmaRead(kernAddr, i2, mapAttr);
       
   623 					Cache::SyncMemoryBeforeDmaWrite(kernAddr, i2, mapAttr);
       
   624 					}
       
   625 				}
       
   626 				break;
       
   627 
       
   628 			default:
       
   629 				r = KErrNotSupported;
       
   630 				break;
       
   631 
       
   632 				}
       
   633 			chunk->Close(0);
       
   634 			}
       
   635 		else
       
   636 			r = KErrNotFound;
       
   637 		NKern::ThreadLeaveCS();
       
   638 		return r;
       
   639 		}
       
   640 
       
   641 
       
   642 	case RSharedChunkLdd::EIsDestroyed:
       
   643 		{
       
   644 		NKern::ThreadEnterCS();
       
   645 		TInt r = WaitForIdle2();
       
   646 		NKern::ThreadLeaveCS();
       
   647 		if (r==KErrNone)
       
   648 			return __e32_atomic_load_acq32(&ChunkDestroyedCount);
       
   649 		return 0;		// never went idle so can't have been destroyed
       
   650 		}
       
   651 
       
   652 
       
   653 	case RSharedChunkLdd::ECloseChunk:
       
   654 		{
       
   655 		NKern::ThreadEnterCS();
       
   656 
       
   657 		// Claim ownership of the chunk
       
   658 		LockWait();
       
   659 		DChunk* chunk=iChunk;
       
   660 		iChunk = 0;
       
   661 		LockSignal();
       
   662 
       
   663 		// Close the chunk
       
   664 		if(chunk)
       
   665 			r = Kern::ChunkClose(chunk);
       
   666 		else
       
   667 			r = KErrNotFound;
       
   668 
       
   669 		NKern::ThreadLeaveCS();
       
   670 		return r;
       
   671 		}
       
   672 
       
   673 
       
   674 	case RSharedChunkLdd::ECheckMemory:
       
   675 	case RSharedChunkLdd::EReadMemory:
       
   676 	case RSharedChunkLdd::EWriteMemory:
       
   677 		{
       
   678 		TUint32 value=0;
       
   679 
       
   680 		NKern::ThreadEnterCS();
       
   681 		TLinAddr kernAddr;
       
   682 		TInt maxSize;
       
   683 		DChunk* chunk=OpenChunk(&kernAddr,&maxSize);
       
   684 		if(chunk)
       
   685 			{
       
   686 			if((TUint)i1>=(TUint)maxSize)
       
   687 				r = KErrArgument;
       
   688 			else
       
   689 				{
       
   690 				TInt addr = kernAddr+i1;
       
   691 #ifdef _DEBUG
       
   692 				TInt debugMask = Kern::CurrentThread().iDebugMask;
       
   693 				Kern::CurrentThread().iDebugMask = debugMask&~(1<<KPANIC);
       
   694 #endif
       
   695 				XTRAP(r, XT_DEFAULT, 
       
   696 					if(aFunction==RSharedChunkLdd::ECheckMemory)
       
   697 						ReadByte((volatile TUint8*)addr);
       
   698 					else if(aFunction==RSharedChunkLdd::EReadMemory)
       
   699 						value = *(volatile TUint32*)addr;
       
   700 					else if(aFunction==RSharedChunkLdd::EWriteMemory)
       
   701 						*(volatile TUint32*)addr = i2;
       
   702 					);
       
   703 #ifdef _DEBUG
       
   704 				Kern::CurrentThread().iDebugMask = debugMask;
       
   705 #endif
       
   706 				if(aFunction==RSharedChunkLdd::ECheckMemory)
       
   707 					r = r==KErrNone;
       
   708 				}
       
   709 			chunk->Close(0);
       
   710 			}
       
   711 		else
       
   712 			r = KErrNotFound;
       
   713 
       
   714 		NKern::ThreadLeaveCS();
       
   715 
       
   716 		if(aFunction==RSharedChunkLdd::EReadMemory)
       
   717 			kumemput32(a2,&value,sizeof(value));
       
   718 
       
   719 		return r;
       
   720 		}
       
   721 
       
   722 
       
   723 	case RSharedChunkLdd::EDfcReadWrite:
       
   724 	case RSharedChunkLdd::EIsrReadWrite:
       
   725 		{
       
   726 		TUint32 value=0;
       
   727 		kumemget32(&value,a2,sizeof(value));
       
   728 
       
   729 		NKern::ThreadEnterCS();
       
   730 		TLinAddr kernAddr;
       
   731 		TInt maxSize;
       
   732 		DChunk* chunk=OpenChunk(&kernAddr,&maxSize);
       
   733 		if(chunk)
       
   734 			{
       
   735 			if((TUint)i1>=(TUint)maxSize)
       
   736 				r = KErrArgument;
       
   737 			else
       
   738 				{
       
   739 				TInt addr = kernAddr+i1;
       
   740 				if(aFunction==RSharedChunkLdd::EDfcReadWrite)
       
   741 					value = DfcReadWrite((TUint32*)addr,value);
       
   742 				else if(aFunction==RSharedChunkLdd::EIsrReadWrite)
       
   743 					value = IsrReadWrite((TUint32*)addr,value);
       
   744 				r = KErrNone;
       
   745 				}
       
   746 			chunk->Close(0);
       
   747 			}
       
   748 		else
       
   749 			r = KErrNotFound;
       
   750 		NKern::ThreadLeaveCS();
       
   751 
       
   752 		kumemput32(a2,&value,sizeof(value));
       
   753 		return r;
       
   754 		}
       
   755 
       
   756 
       
   757 	case RSharedChunkLdd::ETestOpenAddress:
       
   758 		{
       
   759 		NKern::ThreadEnterCS();
       
   760 
       
   761 		TLinAddr kernAddr;
       
   762 		DChunk* chunk=OpenChunk(&kernAddr);
       
   763 		if(!chunk)
       
   764 			{
       
   765 			NKern::ThreadLeaveCS();
       
   766 			return KErrNotReady;
       
   767 			}
       
   768 
       
   769 		TInt offset;
       
   770 		DChunk* chunk2 = Kern::OpenSharedChunk(0,a1,EFalse,offset);
       
   771 		if(chunk2)
       
   772 			{
       
   773 			if(chunk2!=chunk)
       
   774 				r = KErrGeneral;
       
   775 			else
       
   776 				r = KErrNone;
       
   777 			chunk2->Close(0);
       
   778 			}
       
   779 		else
       
   780 			r = KErrNotFound;
       
   781 
       
   782 		chunk->Close(0);
       
   783 
       
   784 		NKern::ThreadLeaveCS();
       
   785 		return r;
       
   786 		}
       
   787 
       
   788 	case RSharedChunkLdd::ETestOpenHandle:
       
   789 		{
       
   790 		NKern::ThreadEnterCS();
       
   791 
       
   792 		TLinAddr kernAddr;
       
   793 		DChunk* chunk=OpenChunk(&kernAddr);
       
   794 		if(!chunk)
       
   795 			{
       
   796 			NKern::ThreadLeaveCS();
       
   797 			return KErrNotReady;
       
   798 			}
       
   799 
       
   800 		DChunk* chunk2 = Kern::OpenSharedChunk(0,i1,EFalse);
       
   801 		if(chunk2)
       
   802 			{
       
   803 			if(chunk2==chunk)
       
   804 				r = KErrNone;
       
   805 			else
       
   806 				r = KErrGeneral;
       
   807 			chunk2->Close(0);
       
   808 			}
       
   809 		else
       
   810 			r = KErrNotFound;
       
   811 
       
   812 		chunk->Close(0);
       
   813 
       
   814 		NKern::ThreadLeaveCS();
       
   815 		return r;
       
   816 		}
       
   817 
       
   818 	case RSharedChunkLdd::ETestAddress:
       
   819 		{
       
   820 		NKern::ThreadEnterCS();
       
   821 
       
   822 		TLinAddr kernAddr;
       
   823 		DChunk* chunk=OpenChunk(&kernAddr);
       
   824 		if(!chunk)
       
   825 			{
       
   826 			NKern::ThreadLeaveCS();
       
   827 			return KErrNotReady;
       
   828 			}
       
   829 
       
   830 		TLinAddr kernAddr2;
       
   831 		r = Kern::ChunkAddress(chunk,i1,i2,kernAddr2);
       
   832 		if(r==KErrNone)
       
   833 			if(kernAddr2!=kernAddr+i1)
       
   834 				r = KErrGeneral;
       
   835 
       
   836 		chunk->Close(0);
       
   837 
       
   838 		NKern::ThreadLeaveCS();
       
   839 		return r;
       
   840 		}
       
   841 		
       
   842 	case RSharedChunkLdd::EChunkUserBase:
       
   843 		{
       
   844 		NKern::ThreadEnterCS();
       
   845 
       
   846 		DChunk* chunk=OpenChunk();
       
   847 		if(!chunk)
       
   848 			{
       
   849 			NKern::ThreadLeaveCS();
       
   850 			return KErrNotReady;
       
   851 			}
       
   852 
       
   853 		TUint8* baseAddress = Kern::ChunkUserBase(chunk, &Kern::CurrentThread());
       
   854 
       
   855 		chunk->Close(0);
       
   856 		if(a1)
       
   857 			kumemput32(a1,(TAny*)&baseAddress,4);
       
   858 
       
   859 		NKern::ThreadLeaveCS();
       
   860 		return KErrNone;
       
   861 		}		
       
   862 
       
   863 	case RSharedChunkLdd::EChunkCloseAndFree:
       
   864 		{
       
   865 #ifdef __EPOC32__
       
   866 		// Allocate and then commit some physical ram to a chunk
       
   867 		NKern::ThreadEnterCS();
       
   868 		const TUint KPhysPages = 5;
       
   869 		TUint pageSize =	Kern::RoundToPageSize(1);
       
   870 		TUint physBytes = KPhysPages * pageSize;
       
   871 		TPhysAddr addrArray[KPhysPages];
       
   872 		TLinAddr linAddr;
       
   873 		TUint32 mapAttr;
       
   874 		DChunk* chunk;
       
   875 
       
   876 		TChunkCreateInfo chunkInfo;
       
   877 		chunkInfo.iType			= TChunkCreateInfo::ESharedKernelSingle;
       
   878 		chunkInfo.iMaxSize		= physBytes;
       
   879 		chunkInfo.iMapAttr		= EMapAttrFullyBlocking;
       
   880 		chunkInfo.iOwnsMemory	= EFalse;
       
   881 
       
   882 		r = Kern::ChunkCreate(chunkInfo, chunk, linAddr, mapAttr);
       
   883 		if (r != KErrNone)
       
   884 			{
       
   885 			NKern::ThreadLeaveCS();
       
   886 			return r;
       
   887 			}
       
   888 		r = Epoc::AllocPhysicalRam(KPhysPages, addrArray);
       
   889 		if (r != KErrNone)
       
   890 			{
       
   891 			Kern::ChunkClose(chunk);
       
   892 			NKern::ThreadLeaveCS();
       
   893 			return r;
       
   894 			}
       
   895 		r = Kern::ChunkCommitPhysical(chunk, 0, physBytes, addrArray);
       
   896 		if (r != KErrNone)
       
   897 			{
       
   898 			Kern::ChunkClose(chunk);
       
   899 			r = Epoc::FreePhysicalRam(KPhysPages, addrArray);
       
   900 			NKern::ThreadLeaveCS();
       
   901 			return r;
       
   902 			}
       
   903 		// Now attempt to free the physical ram immediately after the chunk 
       
   904 		// has been closed.
       
   905 		Kern::ChunkClose(chunk);
       
   906 		r = Epoc::FreePhysicalRam(KPhysPages, addrArray);
       
   907 		NKern::ThreadLeaveCS();
       
   908 		return r;
       
   909 #endif
       
   910 		}
       
   911 
       
   912 	default:
       
   913 		return KErrNotSupported;
       
   914 		}
       
   915 	}
       
   916