os/kernelhwsrv/kerneltest/e32test/mmu/d_sharedchunk.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     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 		TInt isThreadLocal = (TInt)a1;
   478 		TOwnerType ownertype;
   479 		if (isThreadLocal)
   480 			ownertype = EOwnerThread;
   481 		else
   482 			ownertype = EOwnerProcess;
   483 
   484 		NKern::ThreadEnterCS();
   485 		DChunk* chunk=OpenChunk();
   486 		if(chunk)
   487 			{
   488 			r = Kern::MakeHandleAndOpen(0,chunk,ownertype);
   489 			chunk->Close(0);
   490 			}
   491 		else
   492 			r = KErrNotFound;
   493 		NKern::ThreadLeaveCS();
   494 		return r;
   495 		}
   496 
   497 
   498 	case RSharedChunkLdd::ECloseChunkHandle:
   499 		{
   500 		NKern::ThreadEnterCS();
   501 		r = Kern::CloseHandle(0,i1);
   502 		NKern::ThreadLeaveCS();
   503 		return r;
   504 		}
   505 
   506 
   507 	case RSharedChunkLdd::ECommitMemory:
   508 		{
   509 		NKern::ThreadEnterCS();
   510 		TUint32 chunkKernelAddress;
   511 		DChunk* chunk=OpenChunk(&chunkKernelAddress);
   512 		if(chunk)
   513 			{
   514 			TInt type = i1&ECommitTypeMask;
   515 			i1 &= ~ECommitTypeMask;
   516 			switch(type)
   517 				{
   518 			case EDiscontiguous:
   519 				r = Kern::ChunkCommit(chunk,i1,i2);
   520 				break;
   521 
   522 			case EContiguous:
   523 				{
   524 				TUint32 physAddr=~0u;
   525 				r = Kern::ChunkCommitContiguous(chunk,i1,i2,physAddr);
   526 				if(r!=KErrNone || i2==0)
   527 					break;
   528 				if(physAddr==~0u)
   529 					{ r=KErrGeneral; break; }
   530 
   531 				// Check that ChunkPhysicalAddress returns addresses consistant with the commit
   532 				TUint32 kernAddr;
   533 				TUint32 mapAttr;
   534 				TUint32 physAddr2;
   535 				r = Kern::ChunkPhysicalAddress(chunk, i1, i2, kernAddr, mapAttr, physAddr2);
   536 				if(r==KErrNone)
   537 					if(kernAddr!=chunkKernelAddress+i1 || physAddr2!=physAddr)
   538 						r=KErrGeneral;
   539 
   540 				if(r==KErrNone)
   541 					{
   542 					// Exercise memory sync functions
   543 					Cache::SyncMemoryBeforeDmaRead(kernAddr, i2, mapAttr);
   544 					Cache::SyncMemoryBeforeDmaWrite(kernAddr, i2, mapAttr);
   545 					}
   546 				}
   547 				break;
   548 
   549 			case EDiscontiguousPhysical|EBadPhysicalAddress:
   550 			case EDiscontiguousPhysical:
   551 				{
   552 				TUint32 physAddr;
   553 				r = iFactory->AllocMemory(i2,physAddr);
   554 				if(r!=KErrNone)
   555 					break;
   556 
   557 				TInt pageSize =	Kern::RoundToPageSize(1);
   558 				TInt numPages = Kern::RoundToPageSize(i2)/pageSize;
   559 				TUint32* physAddrList = new TUint32[numPages];
   560 				TInt i;
   561 				for(i=0; i<numPages; i++)
   562 					physAddrList[i] = physAddr+i*pageSize;
   563 				if(type&EBadPhysicalAddress)
   564 					physAddrList[i-1] |= 1;
   565 				r = Kern::ChunkCommitPhysical(chunk,i1,i2,physAddrList);
   566 				delete[] physAddrList;
   567 				if(r!=KErrNone || i2==0)
   568 					{
   569 					iFactory->FreeMemory(i2,physAddr);
   570 					break;
   571 					}
   572 
   573 				// Check that ChunkPhysicalAddress returns the same addresses we used in the commit
   574 				TUint32 kernAddr;
   575 				TUint32 mapAttr;
   576 				TUint32 physAddr2;
   577 				TUint32* physAddrList2 = new TUint32[numPages];
   578 				r = Kern::ChunkPhysicalAddress(chunk, i1, i2, kernAddr, mapAttr, physAddr2, physAddrList2);
   579 				if(r==KErrNone)
   580 					{
   581 					if(kernAddr!=chunkKernelAddress+i1 || physAddr2!=physAddr)
   582 						r=KErrGeneral;
   583 					else
   584 						for(i=0; i<numPages; i++)
   585 							if(physAddrList2[i] != physAddr+i*pageSize)
   586 								r = KErrGeneral;
   587 					}
   588 				delete[] physAddrList2;
   589 
   590 				if(r==KErrNone)
   591 					{
   592 					// Exercise memory sync functions
   593 					Cache::SyncMemoryBeforeDmaRead(kernAddr, i2, mapAttr);
   594 					Cache::SyncMemoryBeforeDmaWrite(kernAddr, i2, mapAttr);
   595 					}
   596 				}
   597 				break;
   598 
   599 			case EContiguousPhysical|EBadPhysicalAddress:
   600 			case EContiguousPhysical:
   601 				{
   602 				TUint32 physAddr;
   603 				r = iFactory->AllocMemory(i2,physAddr);
   604 				if(r==KErrNone)
   605 					{
   606 					if(type&EBadPhysicalAddress)
   607 						r = Kern::ChunkCommitPhysical(chunk,i1,i2,physAddr|1);
   608 					else
   609 						r = Kern::ChunkCommitPhysical(chunk,i1,i2,physAddr);
   610 					}
   611 				if(r!=KErrNone || i2==0)
   612 					{
   613 					iFactory->FreeMemory(i2,physAddr);
   614 					break;
   615 					}
   616 
   617 				// Check that ChunkPhysicalAddress returns the same addresses we used in the commit
   618 				TUint32 kernAddr;
   619 				TUint32 mapAttr;
   620 				TUint32 physAddr2;
   621 				r = Kern::ChunkPhysicalAddress(chunk, i1, i2, kernAddr, mapAttr, physAddr2);
   622 				if(r==KErrNone)
   623 					if(kernAddr!=chunkKernelAddress+i1 || physAddr2!=physAddr)
   624 						r=KErrGeneral;
   625 
   626 				if(r==KErrNone)
   627 					{
   628 					// Exercise memory sync functions
   629 					Cache::SyncMemoryBeforeDmaRead(kernAddr, i2, mapAttr);
   630 					Cache::SyncMemoryBeforeDmaWrite(kernAddr, i2, mapAttr);
   631 					}
   632 				}
   633 				break;
   634 
   635 			default:
   636 				r = KErrNotSupported;
   637 				break;
   638 
   639 				}
   640 			chunk->Close(0);
   641 			}
   642 		else
   643 			r = KErrNotFound;
   644 		NKern::ThreadLeaveCS();
   645 		return r;
   646 		}
   647 
   648 
   649 	case RSharedChunkLdd::EIsDestroyed:
   650 		{
   651 		NKern::ThreadEnterCS();
   652 		TInt r = WaitForIdle2();
   653 		NKern::ThreadLeaveCS();
   654 		if (r==KErrNone)
   655 			return __e32_atomic_load_acq32(&ChunkDestroyedCount);
   656 		return 0;		// never went idle so can't have been destroyed
   657 		}
   658 
   659 
   660 	case RSharedChunkLdd::ECloseChunk:
   661 		{
   662 		NKern::ThreadEnterCS();
   663 
   664 		// Claim ownership of the chunk
   665 		LockWait();
   666 		DChunk* chunk=iChunk;
   667 		iChunk = 0;
   668 		LockSignal();
   669 
   670 		// Close the chunk
   671 		if(chunk)
   672 			r = Kern::ChunkClose(chunk);
   673 		else
   674 			r = KErrNotFound;
   675 
   676 		NKern::ThreadLeaveCS();
   677 		return r;
   678 		}
   679 
   680 
   681 	case RSharedChunkLdd::ECheckMemory:
   682 	case RSharedChunkLdd::EReadMemory:
   683 	case RSharedChunkLdd::EWriteMemory:
   684 		{
   685 		TUint32 value=0;
   686 
   687 		NKern::ThreadEnterCS();
   688 		TLinAddr kernAddr;
   689 		TInt maxSize;
   690 		DChunk* chunk=OpenChunk(&kernAddr,&maxSize);
   691 		if(chunk)
   692 			{
   693 			if((TUint)i1>=(TUint)maxSize)
   694 				r = KErrArgument;
   695 			else
   696 				{
   697 				TInt addr = kernAddr+i1;
   698 #ifdef _DEBUG
   699 				TInt debugMask = Kern::CurrentThread().iDebugMask;
   700 				Kern::CurrentThread().iDebugMask = debugMask&~(1<<KPANIC);
   701 #endif
   702 				XTRAP(r, XT_DEFAULT, 
   703 					if(aFunction==RSharedChunkLdd::ECheckMemory)
   704 						ReadByte((volatile TUint8*)addr);
   705 					else if(aFunction==RSharedChunkLdd::EReadMemory)
   706 						value = *(volatile TUint32*)addr;
   707 					else if(aFunction==RSharedChunkLdd::EWriteMemory)
   708 						*(volatile TUint32*)addr = i2;
   709 					);
   710 #ifdef _DEBUG
   711 				Kern::CurrentThread().iDebugMask = debugMask;
   712 #endif
   713 				if(aFunction==RSharedChunkLdd::ECheckMemory)
   714 					r = r==KErrNone;
   715 				}
   716 			chunk->Close(0);
   717 			}
   718 		else
   719 			r = KErrNotFound;
   720 
   721 		NKern::ThreadLeaveCS();
   722 
   723 		if(aFunction==RSharedChunkLdd::EReadMemory)
   724 			kumemput32(a2,&value,sizeof(value));
   725 
   726 		return r;
   727 		}
   728 
   729 
   730 	case RSharedChunkLdd::EDfcReadWrite:
   731 	case RSharedChunkLdd::EIsrReadWrite:
   732 		{
   733 		TUint32 value=0;
   734 		kumemget32(&value,a2,sizeof(value));
   735 
   736 		NKern::ThreadEnterCS();
   737 		TLinAddr kernAddr;
   738 		TInt maxSize;
   739 		DChunk* chunk=OpenChunk(&kernAddr,&maxSize);
   740 		if(chunk)
   741 			{
   742 			if((TUint)i1>=(TUint)maxSize)
   743 				r = KErrArgument;
   744 			else
   745 				{
   746 				TInt addr = kernAddr+i1;
   747 				if(aFunction==RSharedChunkLdd::EDfcReadWrite)
   748 					value = DfcReadWrite((TUint32*)addr,value);
   749 				else if(aFunction==RSharedChunkLdd::EIsrReadWrite)
   750 					value = IsrReadWrite((TUint32*)addr,value);
   751 				r = KErrNone;
   752 				}
   753 			chunk->Close(0);
   754 			}
   755 		else
   756 			r = KErrNotFound;
   757 		NKern::ThreadLeaveCS();
   758 
   759 		kumemput32(a2,&value,sizeof(value));
   760 		return r;
   761 		}
   762 
   763 
   764 	case RSharedChunkLdd::ETestOpenAddress:
   765 		{
   766 		NKern::ThreadEnterCS();
   767 
   768 		TLinAddr kernAddr;
   769 		DChunk* chunk=OpenChunk(&kernAddr);
   770 		if(!chunk)
   771 			{
   772 			NKern::ThreadLeaveCS();
   773 			return KErrNotReady;
   774 			}
   775 
   776 		TInt offset;
   777 		DChunk* chunk2 = Kern::OpenSharedChunk(0,a1,EFalse,offset);
   778 		if(chunk2)
   779 			{
   780 			if(chunk2!=chunk)
   781 				r = KErrGeneral;
   782 			else
   783 				r = KErrNone;
   784 			chunk2->Close(0);
   785 			}
   786 		else
   787 			r = KErrNotFound;
   788 
   789 		chunk->Close(0);
   790 
   791 		NKern::ThreadLeaveCS();
   792 		return r;
   793 		}
   794 
   795 	case RSharedChunkLdd::ETestOpenHandle:
   796 		{
   797 		NKern::ThreadEnterCS();
   798 
   799 		TLinAddr kernAddr;
   800 		DChunk* chunk=OpenChunk(&kernAddr);
   801 		if(!chunk)
   802 			{
   803 			NKern::ThreadLeaveCS();
   804 			return KErrNotReady;
   805 			}
   806 
   807 		DChunk* chunk2 = Kern::OpenSharedChunk(0,i1,EFalse);
   808 		if(chunk2)
   809 			{
   810 			if(chunk2==chunk)
   811 				r = KErrNone;
   812 			else
   813 				r = KErrGeneral;
   814 			chunk2->Close(0);
   815 			}
   816 		else
   817 			r = KErrNotFound;
   818 
   819 		chunk->Close(0);
   820 
   821 		NKern::ThreadLeaveCS();
   822 		return r;
   823 		}
   824 
   825 	case RSharedChunkLdd::ETestAddress:
   826 		{
   827 		NKern::ThreadEnterCS();
   828 
   829 		TLinAddr kernAddr;
   830 		DChunk* chunk=OpenChunk(&kernAddr);
   831 		if(!chunk)
   832 			{
   833 			NKern::ThreadLeaveCS();
   834 			return KErrNotReady;
   835 			}
   836 
   837 		TLinAddr kernAddr2;
   838 		r = Kern::ChunkAddress(chunk,i1,i2,kernAddr2);
   839 		if(r==KErrNone)
   840 			if(kernAddr2!=kernAddr+i1)
   841 				r = KErrGeneral;
   842 
   843 		chunk->Close(0);
   844 
   845 		NKern::ThreadLeaveCS();
   846 		return r;
   847 		}
   848 		
   849 	case RSharedChunkLdd::EChunkUserBase:
   850 		{
   851 		NKern::ThreadEnterCS();
   852 
   853 		DChunk* chunk=OpenChunk();
   854 		if(!chunk)
   855 			{
   856 			NKern::ThreadLeaveCS();
   857 			return KErrNotReady;
   858 			}
   859 
   860 		TUint8* baseAddress = Kern::ChunkUserBase(chunk, &Kern::CurrentThread());
   861 
   862 		chunk->Close(0);
   863 		if(a1)
   864 			kumemput32(a1,(TAny*)&baseAddress,4);
   865 
   866 		NKern::ThreadLeaveCS();
   867 		return KErrNone;
   868 		}		
   869 
   870 	case RSharedChunkLdd::EChunkCloseAndFree:
   871 		{
   872 #ifdef __EPOC32__
   873 		// Allocate and then commit some physical ram to a chunk
   874 		NKern::ThreadEnterCS();
   875 		const TUint KPhysPages = 5;
   876 		TUint pageSize =	Kern::RoundToPageSize(1);
   877 		TUint physBytes = KPhysPages * pageSize;
   878 		TPhysAddr addrArray[KPhysPages];
   879 		TLinAddr linAddr;
   880 		TUint32 mapAttr;
   881 		DChunk* chunk;
   882 
   883 		TChunkCreateInfo chunkInfo;
   884 		chunkInfo.iType			= TChunkCreateInfo::ESharedKernelSingle;
   885 		chunkInfo.iMaxSize		= physBytes;
   886 		chunkInfo.iMapAttr		= EMapAttrFullyBlocking;
   887 		chunkInfo.iOwnsMemory	= EFalse;
   888 
   889 		r = Kern::ChunkCreate(chunkInfo, chunk, linAddr, mapAttr);
   890 		if (r != KErrNone)
   891 			{
   892 			NKern::ThreadLeaveCS();
   893 			return r;
   894 			}
   895 		r = Epoc::AllocPhysicalRam(KPhysPages, addrArray);
   896 		if (r != KErrNone)
   897 			{
   898 			Kern::ChunkClose(chunk);
   899 			NKern::ThreadLeaveCS();
   900 			return r;
   901 			}
   902 		r = Kern::ChunkCommitPhysical(chunk, 0, physBytes, addrArray);
   903 		if (r != KErrNone)
   904 			{
   905 			Kern::ChunkClose(chunk);
   906 			r = Epoc::FreePhysicalRam(KPhysPages, addrArray);
   907 			NKern::ThreadLeaveCS();
   908 			return r;
   909 			}
   910 		// Now attempt to free the physical ram immediately after the chunk 
   911 		// has been closed.
   912 		Kern::ChunkClose(chunk);
   913 		r = Epoc::FreePhysicalRam(KPhysPages, addrArray);
   914 		NKern::ThreadLeaveCS();
   915 		return r;
   916 #endif
   917 		}
   918 
   919 	default:
   920 		return KErrNotSupported;
   921 		}
   922 	}
   923