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