os/kernelhwsrv/kerneltest/e32test/mmu/t_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\t_sharedchunk.cpp
    15 // Overview:
    16 // Test sharing an RChunk with a logical device
    17 // API Information:
    18 // RChunk
    19 // Details:
    20 // - Load and open the logical device driver ("D_SHAREDCHUNK"). Verify
    21 // results.
    22 // - Test and verify results of creating shared chunks under OOM conditions. Also verify 
    23 // creating a chunk with a bad type, bad size and too large all fail as 
    24 // expected.
    25 // - Test and verify opening and closing chunk user handles work as expected.
    26 // - Test and verify thread local and process local handles work as expected
    27 // - Test and verify setting restrictions on RChunk if created as shared chunk are as expected.
    28 // - Test and verify memory access for multiply and singly shared chunks, 
    29 // is as expected. Including IPC, kernel, DFC and ISR reads & writes.
    30 // - Test and verify discontinuous memory commits for multiply and singly 
    31 // shared chunks are as expected.
    32 // - Test and verify continuous memory commits for multiply and singly shared
    33 // chunks are as expected.
    34 // - Test and verify discontinuous and continuous physical memory commits for 
    35 // multiply and singly shared chunks is as expected.
    36 // - Test Kern::OpenSharedChunk for multiply and singly shared chunks. Verify
    37 // results are as expected.
    38 // - Test that physical memory can be freed immediately after the chunk that mapped 
    39 // it has been closed.
    40 // Platforms/Drives/Compatibility:
    41 // All.
    42 // Assumptions/Requirement/Pre-requisites:
    43 // Failures and causes:
    44 // Base Port information:
    45 // 
    46 //
    47 
    48 //! @file
    49 //! @SYMTestCaseID KBASE-T_SHAREDCHUNK
    50 //! @SYMREQ 3699
    51 //! @SYMTestPriority High
    52 //! @SYMTestActions Check creation, memory allocation and access to Shared Chunks
    53 //! @SYMTestExpectedResults Test runs until this message is emitted: RTEST: SUCCESS : T_SHAREDCHUNK test completed O.K.
    54 //! @SYMTestType UT
    55 #define __E32TEST_EXTENSION__
    56 
    57 #include "d_sharedchunk.h"
    58 #include "d_gobble.h"
    59 #include <e32test.h>
    60 #include <e32hal.h>
    61 #include "u32std.h"
    62 #include <u32hal.h>
    63 #include <e32svr.h>
    64 #include <f32dbg.h>
    65 #include <e32def.h>
    66 #include <e32def_private.h>
    67 #include "freeram.h"
    68 
    69 enum TSlaveCommand
    70 	{
    71 	ESlaveCheckChunk,
    72 	ESlaveCreateChunk,
    73 	};
    74 
    75 //
    76 // Global data
    77 //
    78 
    79 
    80 RSharedChunkLdd Ldd;
    81 RChunk TheChunk;
    82 TInt PageSize;
    83 TUint32 MemModelAttributes;
    84 TBool PhysicalCommitSupported;
    85 TBool CachingAttributesSupported;
    86 TUint8 BssMem[100];
    87 
    88 const TUint ChunkSize = 0x400000;	// 4 meg reserved space for test chunk
    89 
    90 _LIT(KSecondProcessName,"t_sharedchunk");
    91 #ifdef __T_SHAREDCHUNKF__
    92 _LIT(KOtherProcessName,"t_sharedchunk");
    93 LOCAL_D RTest test(_L("T_SHAREDCHUNKF"));
    94 #else
    95 _LIT(KOtherProcessName,"t_sharedchunkf");
    96 LOCAL_D RTest test(_L("T_SHAREDCHUNK"));
    97 #endif
    98 
    99 _LIT8(KTestString, "lks4b7qeyfcea5fyaifyaefyi4flwdysuxanabxa");
   100 _LIT8(KTestString2,"jhfcalurnhfirlxszhrvcvduhrvndrucxnshxcsx");
   101 const TUint32 KTestValue = 0x12345678;
   102 const TUint32 KTestValue2 = KTestValue^0x0f0f0f0f;
   103 
   104 //
   105 // Utilitiies for use by tests
   106 //
   107 
   108 
   109 _LIT(KLitKernExec, "KERN-EXEC");
   110 
   111 void CheckFailMessage(const char* n,const char* c,const char* f,TInt r)
   112 	{
   113 	TPtrC8 nn((const TUint8*)n);
   114 	TPtrC8 cc((const TUint8*)c);
   115 	TPtrC8 ff((const TUint8*)f);
   116 	RBuf8 buf;
   117 	buf.Create((nn.Size()+cc.Size()+ff.Size()+64)*2);
   118 	buf.AppendFormat(_L8("\nCHECK failed: %S == 0x%x but was tested for %S%S\n"),&ff,r,&cc,&nn);
   119 	test.Printf(buf.Expand());
   120 	buf.Close();
   121 	}
   122 
   123 #define CHECK(n,c,f) \
   124 	{	\
   125 	TInt _r=(TInt)(f);	\
   126 	if(!((TInt)(n)c(_r)))	\
   127 		{	\
   128 		CheckFailMessage(#n,#c,#f,_r);	\
   129 		test(0);	\
   130 		}	\
   131 	}
   132 
   133 #define KCHECK_MEMORY(result,offset)	\
   134 	{	\
   135 	/* test.Printf(_L("check offset 0x%08x\r"),offset); */	\
   136 	CHECK(result,==,Ldd.CheckMemory(offset));	\
   137 	}
   138 
   139 #define KWRITE_MEMORY(offset,value)	\
   140 	{	\
   141 	CHECK(KErrNone,==,Ldd.WriteMemory(offset,value));	\
   142 	}
   143 
   144 #define UREAD_MEMORY(offset,value)	\
   145 	{	\
   146 	CHECK(value,==,*(TUint*)(Base+offset));	\
   147 	}
   148 
   149 inline TUint32 Tag(TUint32 offset)
   150 	{ return (69069u*(offset*4+1)); }
   151 
   152 TInt MemoryAccessThread(TAny* aAddress)
   153 	{
   154 	TInt r = *(volatile TUint8*)aAddress;	// read from aAddress
   155 	(void)r;
   156 	return 0;
   157 	}
   158 
   159 TInt CheckUMemory(TAny* aAddress)
   160 	{
   161 	RThread thread;
   162 	thread.Create(KNullDesC,MemoryAccessThread,PageSize,&User::Heap(),aAddress);
   163 	TRequestStatus status;
   164 	thread.Logon(status);
   165 	TBool jit = User::JustInTime();
   166 	User::SetJustInTime(EFalse);
   167 	thread.Resume();
   168 	User::WaitForRequest(status);
   169 	User::SetJustInTime(jit);
   170 	TInt r;
   171 	if(thread.ExitType()==EExitKill && thread.ExitReason()==0)
   172 		r = 1;	// Memory access pass
   173 	else if(thread.ExitType()==EExitPanic && thread.ExitCategory()==KLitKernExec && thread.ExitReason()==3 )
   174 		r = 0;	// Memory access failed
   175 	else
   176 		r = -1;	// Unexpected result
   177 	CLOSE_AND_WAIT(thread);
   178 	return r;
   179 	}
   180 
   181 #define UCHECK_MEMORY(result,offset)	\
   182 	{	\
   183 	/* test.Printf(_L("ucheck offset 0x%08x\r"),offset); */	\
   184 	CHECK(result,==,CheckUMemory(Base+offset));	\
   185 	}
   186 
   187 TInt CheckPlatSecPanic(TThreadFunction aThreadFunction,TInt aThreadArgument)
   188 	{
   189 	RThread thread;
   190 	thread.Create(KNullDesC,aThreadFunction,PageSize,&User::Heap(),(TAny*)aThreadArgument);
   191 	TRequestStatus status;
   192 	thread.Logon(status);
   193 	TBool jit = User::JustInTime();
   194 	User::SetJustInTime(EFalse);
   195 	thread.Resume();
   196 	User::WaitForRequest(status);
   197 	User::SetJustInTime(jit);
   198 	TInt r;
   199 	if(thread.ExitType()==EExitPanic && thread.ExitCategory()==KLitKernExec && thread.ExitReason()==46 )
   200 		r = 1;	// PlatSec panic
   201 	else if(thread.ExitType()==EExitKill && thread.ExitReason()==0)
   202 		r = 0;	// Exit without error
   203 	else
   204 		r = -1;	// Unexpected result
   205 	CLOSE_AND_WAIT(thread);
   206 	return r;
   207 	}
   208 
   209 //
   210 // The tests
   211 //
   212 
   213 void CreateWithOomCheck(TInt aCreateFlags)
   214 	{
   215 	TInt failResult=KErrGeneral;
   216 	for(TInt failCount=1; failCount<1000; failCount++)
   217 		{
   218 		test.Printf(_L("alloc fail count = %d\n"),failCount);
   219 		User::__DbgSetBurstAllocFail(ETrue,RAllocator::EFailNext,failCount,1000);
   220 		__KHEAP_MARK;
   221 		failResult = Ldd.CreateChunk(aCreateFlags);
   222 		if(failResult==KErrNone)
   223 			break;
   224 		CHECK(KErrNoMemory,==,failResult);
   225 		Ldd.IsDestroyed();	// This includes delay to let idle thread do cleanup
   226 		__KHEAP_MARKEND;
   227 		}
   228 	User::__DbgSetAllocFail(ETrue,RAllocator::ENone,0);
   229 	__KHEAP_RESET;
   230 	CHECK(KErrNone,==,failResult);
   231 	}
   232 
   233 void TestCreate()
   234 	{
   235 	test.Start(_L("Creating chunk type Single,OwnsMemory"));
   236 	CreateWithOomCheck(ChunkSize|ESingle|EOwnsMemory);
   237 	CHECK(0,==,Ldd.IsDestroyed());
   238 
   239 	test.Next(_L("Close kernel handle"));
   240 	CHECK(1,==,Ldd.CloseChunk()); // 1==DObject::EObjectDeleted
   241 	CHECK(1,==,Ldd.IsDestroyed());
   242 
   243 	test.Next(_L("Creating chunk type Multiple,OwnsMemory"));
   244 	CreateWithOomCheck(ChunkSize|EMultiple|EOwnsMemory);
   245 	CHECK(0,==,Ldd.IsDestroyed());
   246 
   247 	test.Next(_L("Close kernel handle"));
   248 	CHECK(1,==,Ldd.CloseChunk()); // 1==DObject::EObjectDeleted
   249 	CHECK(1,==,Ldd.IsDestroyed());
   250 
   251 	if(PhysicalCommitSupported)
   252 		{
   253 		test.Next(_L("Creating chunk type Single,!OwnsMemory"));
   254 		CreateWithOomCheck(ChunkSize|ESingle);
   255 		CHECK(0,==,Ldd.IsDestroyed());
   256 
   257 		test.Next(_L("Close kernel handle"));
   258 		CHECK(1,==,Ldd.CloseChunk()); // 1==DObject::EObjectDeleted
   259 		CHECK(1,==,Ldd.IsDestroyed());
   260 
   261 		test.Next(_L("Creating chunk type Multiple,!OwnsMemory"));
   262 		CreateWithOomCheck(ChunkSize|EMultiple);
   263 		CHECK(0,==,Ldd.IsDestroyed());
   264 
   265 		test.Next(_L("Close kernel handle"));
   266 		CHECK(1,==,Ldd.CloseChunk()); // 1==DObject::EObjectDeleted
   267 		CHECK(1,==,Ldd.IsDestroyed());
   268 		}
   269 	else
   270 		{
   271 		test.Next(_L("Try creating unsupported chunk type Single,!OwnsMemory"));
   272 		CHECK(KErrNotSupported,==,Ldd.CreateChunk(ChunkSize|ESingle));
   273 
   274 		test.Next(_L("Try creating unsupported chunk type Multiple,!OwnsMemory"));
   275 		CHECK(KErrNotSupported,==,Ldd.CreateChunk(ChunkSize|EMultiple));
   276 		}
   277 
   278 	test.Next(_L("__KHEAP_MARK"));
   279 	__KHEAP_MARK;
   280 
   281 	test.Next(_L("Creating chunk (bad type)"));
   282 	CHECK(KErrArgument,==,Ldd.CreateChunk(EBadType|EOwnsMemory|ChunkSize));
   283 
   284 	test.Next(_L("Creating chunk (bad size)"));
   285 	CHECK(KErrArgument,==,Ldd.CreateChunk(ESingle|EOwnsMemory|0xffffff00));
   286 
   287 	test.Next(_L("Creating chunk (size too big)"));
   288 	CHECK(KErrNoMemory,==,Ldd.CreateChunk(ESingle|EOwnsMemory|0x7fffff00));
   289 
   290 	test.Next(_L("__KHEAP_MARKEND"));
   291 	__KHEAP_MARKEND;
   292 
   293 	test.End();
   294 	}
   295 
   296 
   297 void OpenWithOomCheck(RChunk& aChunk)
   298 	{
   299 	TInt failResult=KErrGeneral;
   300 	for(TInt failCount=1; failCount<1000; failCount++)
   301 		{
   302 		test.Printf(_L("alloc fail count = %d\n"),failCount);
   303 		User::__DbgSetBurstAllocFail(ETrue,RAllocator::EFailNext,failCount,1000);
   304 		__KHEAP_MARK;
   305 		failResult = Ldd.GetChunkHandle(aChunk);
   306 		if(failResult==KErrNone)
   307 			break;
   308 		CHECK(KErrNoMemory,==,failResult);
   309 		Ldd.IsDestroyed();	// This includes delay to let idle thread do cleanup
   310 		__KHEAP_MARKEND;
   311 		}
   312 	User::__DbgSetAllocFail(ETrue,RAllocator::ENone,0);
   313 	__KHEAP_RESET;
   314 	CHECK(KErrNone,==,failResult);
   315 	}
   316 
   317 void TestHandles()
   318 	{
   319 	TUint ChunkAttribs = ChunkSize|ESingle|EOwnsMemory;
   320 
   321 	test.Start(_L("Create chunk"));
   322 	CHECK(KErrNone,==,Ldd.CreateChunk(ChunkAttribs));
   323 
   324 	test.Next(_L("Open user handle"));
   325 	OpenWithOomCheck(TheChunk);
   326 
   327 	test.Next(_L("Close user handle"));
   328 	TheChunk.Close();
   329 
   330 	test.Next(_L("Check chunk not destroyed"));
   331 	CHECK(0,==,Ldd.IsDestroyed());
   332 
   333 	test.Next(_L("Close kernel handle"));
   334 	CHECK(1,==,Ldd.CloseChunk()); // 1==DObject::EObjectDeleted
   335 
   336 	test.Next(_L("Check chunk destroyed"));
   337 	CHECK(1,==,Ldd.IsDestroyed());
   338 
   339 	// Another chunk - closing handles in reverse order
   340 
   341 	test.Next(_L("Create chunk"));
   342 	CHECK(KErrNone,==,Ldd.CreateChunk(ChunkAttribs));
   343 
   344 	test.Next(_L("Open user handle"));
   345 	OpenWithOomCheck(TheChunk);
   346 
   347 	test.Next(_L("Close kernel handle"));
   348 	CHECK(KErrNone,==,Ldd.CloseChunk());
   349 
   350 	test.Next(_L("Check chunk not destroyed"));
   351 	CHECK(0,==,Ldd.IsDestroyed());
   352 
   353 	test.Next(_L("Using user handle to check chunk info"));
   354 	if((MemModelAttributes&EMemModelTypeMask)!=EMemModelTypeDirect)
   355 		{
   356 		CHECK(0,==,TheChunk.Size());
   357 		}
   358 	CHECK(ChunkSize,==,TheChunk.MaxSize());
   359 
   360 	test.Next(_L("Close user handle"));
   361 	TheChunk.Close();
   362 
   363 	test.Next(_L("Check chunk destroyed"));
   364 	CHECK(1,==,Ldd.IsDestroyed());
   365 
   366 	test.End();
   367 	}
   368 
   369 TInt HandleOwnershipThread(TAny* aArg)
   370 	{
   371 	// Use existing handle and attempt to read from chunk
   372 	TInt handle = (TInt) aArg;
   373 	RChunk chunk;
   374 	chunk.SetHandle(handle);
   375 	TInt r = *(volatile TUint8*)chunk.Base();
   376 	(void)r;
   377 	CLOSE_AND_WAIT(chunk);
   378 	return KErrNone;
   379 	}
   380 
   381 void TestHandleOwnership()
   382 	{
   383 	TUint ChunkAttribs = ChunkSize|ESingle|EOwnsMemory;
   384 	RThread thread;
   385 	TRequestStatus rs;
   386 
   387 	test.Start(_L("Create chunk"));
   388 	CHECK(KErrNone,==,Ldd.CreateChunk(ChunkAttribs));
   389 
   390 	test.Next(_L("Commit page to chunk"));
   391 	CHECK(KErrNone,==,Ldd.CommitMemory(EDiscontiguous,PageSize));
   392 
   393 	test.Next(_L("Check can access memory kernel side"));
   394 	KCHECK_MEMORY(ETrue, 0);
   395 
   396 	// Handle is thread-owned
   397 	test.Next(_L("Open user handle (thread-owned)"));
   398 	CHECK(0,<=,Ldd.GetChunkHandle(TheChunk, ETrue));
   399 
   400 	test.Next(_L("Get memory size info"));
   401 	if((MemModelAttributes&EMemModelTypeMask)!=EMemModelTypeDirect)
   402 		{
   403 		CHECK(PageSize,==,TheChunk.Size());
   404 		}
   405 	CHECK(ChunkSize,==,TheChunk.MaxSize());
   406 	TUint8* Base = TheChunk.Base();
   407 	CHECK(Base,!=,0);
   408 
   409 	test.Next(_L("Check can access memory user side"));
   410 	UCHECK_MEMORY(ETrue, 0);
   411 
   412 	test.Next(_L("Use handle in a new thread"));
   413 	CHECK(KErrNone,==,thread.Create(_L("thread1"), HandleOwnershipThread, KDefaultStackSize, KMinHeapSize, KMinHeapSize, (TAny*)TheChunk.Handle()));
   414 	thread.Logon(rs);
   415 	thread.Resume();
   416 	User::WaitForRequest(rs);
   417 	CHECK(EExitPanic,==,thread.ExitType());
   418 	CHECK(0,==,thread.ExitReason()); // KERN-EXEC 0
   419 	CLOSE_AND_WAIT(thread);
   420 
   421 	test.Next(_L("Close user handle"));
   422 	TheChunk.Close();
   423 
   424 	// Handle is process-owned
   425 	test.Next(_L("Open user handle (process-owned"));
   426 	CHECK(0,<=,Ldd.GetChunkHandle(TheChunk, EFalse));
   427 
   428 	test.Next(_L("Check can access memory user side"));
   429 	UCHECK_MEMORY(ETrue, 0);
   430 
   431 	test.Next(_L("Close kernel handle"));
   432 	CHECK(KErrNone,==,Ldd.CloseChunk());
   433 
   434 	test.Next(_L("Check chunk destroyed"));
   435 	CHECK(0,==,Ldd.IsDestroyed());
   436 
   437 	test.Next(_L("Use handle in a new thread"));
   438 	CHECK(KErrNone,==,thread.Create(_L("thread2"), HandleOwnershipThread, KDefaultStackSize, KMinHeapSize, KMinHeapSize, (TAny*)TheChunk.Handle()));
   439 	thread.Logon(rs);
   440 	thread.Resume();
   441 	User::WaitForRequest(rs);
   442 	CHECK(EExitKill,==,thread.ExitType());
   443 	CHECK(KErrNone,==,thread.ExitReason());
   444 	CLOSE_AND_WAIT(thread);
   445 
   446 	test.Next(_L("Check chunk destroyed"));
   447 	CHECK(1,==,Ldd.IsDestroyed()); // Object was deleted
   448 
   449 	test.End();
   450 	}
   451 
   452 void SetCreateFlags(TUint& aCreateFlags,TCommitType aCommitType)
   453 	{
   454 	if(!((TInt)aCommitType&EPhysicalMask))
   455 		aCreateFlags |= EOwnsMemory;
   456 	else
   457 		aCreateFlags &= ~EOwnsMemory;
   458 	}
   459 
   460 
   461 void TestAccess(TUint aCreateFlags,TCommitType aCommitType)
   462 	{
   463 	const TUint32 offset = 0;
   464 	const TUint32 size = PageSize;
   465 
   466 	SetCreateFlags(aCreateFlags,aCommitType);
   467 
   468 	test.Start(_L("Create chunk"));
   469 	TUint8* kernelAddress;
   470 	CHECK(KErrNone,==,Ldd.CreateChunk(aCreateFlags|ChunkSize,(TAny**)&kernelAddress));
   471 
   472 	if((MemModelAttributes&TUint32(EMemModelAttrNonExProt)) && (MemModelAttributes&EMemModelTypeMask)!=EMemModelTypeDirect)
   473 		{
   474 		test.Next(_L("Check can't access memory"));
   475 		KCHECK_MEMORY(EFalse,offset);
   476 		}
   477 
   478 	test.Next(_L("Commit page to chunk"));
   479 	CHECK(KErrNone,==,Ldd.CommitMemory(aCommitType|offset,size));
   480 
   481 	test.Next(_L("Check can access memory kernel side"));
   482 	KCHECK_MEMORY(ETrue, offset);
   483 
   484 	if((MemModelAttributes&EMemModelAttrKernProt) && (MemModelAttributes&EMemModelTypeMask)!=EMemModelTypeDirect)
   485 		{
   486 		test.Next(_L("Check user side can't access kernel memory"));
   487 		TUint8* Base = kernelAddress;
   488 		UCHECK_MEMORY(EFalse, offset);
   489 		}
   490 
   491 	test.Next(_L("Open user handle"));
   492 	CHECK(KErrNone,==,Ldd.GetChunkHandle(TheChunk));
   493 
   494 	test.Next(_L("Get memory size info"));
   495 	if((MemModelAttributes&EMemModelTypeMask)!=EMemModelTypeDirect)
   496 		{
   497 		CHECK(PageSize,==,TheChunk.Size());
   498 		}
   499 	CHECK(ChunkSize,==,TheChunk.MaxSize());
   500 	TUint8* Base = TheChunk.Base();
   501 	CHECK(Base,!=,0);
   502 
   503 	test.Next(_L("Check can access memory user side"));
   504 	UCHECK_MEMORY(ETrue, offset);
   505 
   506 	test.Next(_L("Check user and kernel access same memory"));
   507 	KWRITE_MEMORY(offset,~Tag(offset));
   508 	UREAD_MEMORY(offset,~Tag(offset));
   509 	KWRITE_MEMORY(offset,Tag(offset));
   510 	UREAD_MEMORY(offset,Tag(offset));
   511 
   512 	test.Next(_L("Close user handle"));
   513 	CHECK(0,==,Ldd.CloseChunkHandle(TheChunk));
   514 	CHECK(0,==,Ldd.IsDestroyed());
   515 
   516 	if((MemModelAttributes&EMemModelAttrKernProt) && (MemModelAttributes&EMemModelTypeMask)!=EMemModelTypeDirect)
   517 		{
   518 		test.Next(_L("Check can no-longer access memory user side"));
   519 		UCHECK_MEMORY(EFalse,offset);
   520 		}
   521 
   522 	test.Next(_L("Check can still access memory kernel side"));
   523 	KCHECK_MEMORY(ETrue, offset);
   524 
   525 	test.Next(_L("Open user handle again"));
   526 	CHECK(KErrNone,==,Ldd.GetChunkHandle(TheChunk));
   527 
   528 	test.Next(_L("Check can access chunk user side again"));
   529 	CHECK(Base,==,TheChunk.Base());
   530 	CHECK(ChunkSize,==,TheChunk.MaxSize());
   531 	if((MemModelAttributes&EMemModelTypeMask)!=EMemModelTypeDirect)
   532 		{
   533 		CHECK(size,==,TheChunk.Size());
   534 		}
   535 	UREAD_MEMORY(offset,Tag(offset));
   536 
   537 	test.Next(_L("Close kernel handle"));
   538 	CHECK(0,==,Ldd.CloseChunk());
   539 	CHECK(0,==,Ldd.IsDestroyed());
   540 
   541 	test.Next(_L("Check can still access chunk user side"));
   542 	CHECK(Base,==,TheChunk.Base());
   543 	CHECK(ChunkSize,==,TheChunk.MaxSize());
   544 	if((MemModelAttributes&EMemModelTypeMask)!=EMemModelTypeDirect)
   545 		{
   546 		CHECK(size,==,TheChunk.Size());
   547 		}
   548 	UREAD_MEMORY(offset,Tag(offset));
   549 
   550 	test.Next(_L("Close user handle"));
   551 	TheChunk.Close();
   552 	CHECK(1,==,Ldd.IsDestroyed());
   553 
   554 	test.Next(_L("Create chunk in another process"));
   555 
   556 	// Create test server
   557 	RServer2 server;
   558 	RMessage2 message;
   559 	TRequestStatus status;
   560 	CHECK(KErrNone,==,server.CreateGlobal(KSecondProcessName));
   561 	server.Receive(message,status);
   562 
   563 	// Launch slave process
   564 	RProcess process;
   565 	CHECK(KErrNone,==,process.Create(KSecondProcessName,KNullDesC));
   566 	CHECK(KErrNone,==,process.SetParameter(1,ESlaveCreateChunk));
   567 	CHECK(KErrNone,==,process.SetParameter(2,(RBusLogicalChannel&)Ldd));
   568 	CHECK(KErrNone,==,process.SetParameter(3,ChunkSize|aCreateFlags));
   569 	CHECK(KErrNone,==,process.SetParameter(4,aCommitType));
   570 	CHECK(KErrNone,==,process.SetParameter(5,PageSize));
   571 	TRequestStatus logon;
   572 	process.Logon(logon);
   573 	process.Resume();
   574 
   575 	// Wait for slave to connect to test server
   576 	User::WaitForRequest(logon,status);
   577 	CHECK(KRequestPending,==,logon.Int())
   578 	CHECK(KErrNone,==,status.Int());
   579 	CHECK(RMessage2::EConnect,==,message.Function());
   580 	message.Complete(KErrNone);
   581 	server.Receive(message,status);
   582 
   583 	// Wait for message
   584 	User::WaitForRequest(logon,status);
   585 	CHECK(KRequestPending,==,logon.Int())
   586 	CHECK(KErrNone,==,status.Int());
   587 	CHECK(0,==,message.Function());
   588 
   589 	test.Next(_L("Check IPC read/write"));
   590 	RBuf8 buf;
   591 	buf.Create(KTestString().Size());
   592 	CHECK(KErrNone,==,message.Read(0,buf));
   593 	CHECK(ETrue,==,buf==KTestString());
   594 	CHECK(KErrNone,==,message.Write(0,KTestString2));
   595 	CHECK(KErrNone,==,message.Read(0,buf));
   596 	CHECK(ETrue,==,buf==KTestString2());
   597 
   598 	test.Next(_L("Check Kernel read/write"));
   599 	TInt n;
   600 	TUint32 value;
   601 	for(n=0; n<KTestString2().Size()-(TInt)sizeof(TInt)+1; n+=sizeof(TInt))
   602 		{
   603 		Ldd.ReadMemory(n,value);
   604 		CHECK(*(TInt*)&KTestString2()[n],==,value);
   605 		CHECK(KErrNone,==,Ldd.WriteMemory(n,*(TInt*)&KTestString()[n]));
   606 		Ldd.ReadMemory(n,value);
   607 		CHECK(*(TInt*)&KTestString()[n],==,value);
   608 		}
   609 	CHECK(KErrNone,==,message.Read(0,buf));
   610 	CHECK(ETrue,==,buf==KTestString());
   611 	buf.Close();
   612 
   613 	test.Next(_L("Check read/write from DFC"));
   614 	CHECK(KErrNone,==,Ldd.WriteMemory(0,KTestValue));
   615 	value = KTestValue2;
   616 	CHECK(KErrNone,==,Ldd.DfcReadWrite(0,value));
   617 	CHECK(KTestValue,==,value);
   618 	CHECK(KErrNone,==,Ldd.ReadMemory(0,value));
   619 	CHECK(KTestValue2,==,value);
   620 	
   621 	test.Next(_L("Check read/write from ISR"));
   622 	CHECK(KErrNone,==,Ldd.WriteMemory(0,KTestValue));
   623 	value = KTestValue2;
   624 	CHECK(KErrNone,==,Ldd.IsrReadWrite(0,value));
   625 	CHECK(KTestValue,==,value);
   626 	CHECK(KErrNone,==,Ldd.ReadMemory(0,value));
   627 	CHECK(KTestValue2,==,value);
   628 
   629 	test.Next(_L("Cleanup resources"));
   630 	server.Close();
   631 	User::WaitForRequest(logon);
   632 	CLOSE_AND_WAIT(process);
   633 
   634 	test.End();
   635 	}
   636 
   637 
   638 RProcess OtherProcess;
   639 
   640 TInt HandleShare(TAny* aHandle)
   641 	{
   642 	TInt r=OtherProcess.Create(KOtherProcessName,KNullDesC,EOwnerProcess);
   643 	if(r==KErrNone)
   644 		{
   645 		r = OtherProcess.SetParameter(1,(RChunk&)aHandle);
   646 		}
   647 	return r;
   648 	}
   649 
   650 void TestRestrictions(TInt aAttrib)
   651 	{
   652 	TUint ChunkAttribs = ChunkSize|aAttrib|EOwnsMemory;
   653 
   654 	test.Start(_L("Create chunk"));
   655 	CHECK(KErrNone,==,Ldd.CreateChunk(ChunkAttribs));
   656 
   657 	test.Next(_L("Open user handle"));
   658 	CHECK(KErrNone,==,Ldd.GetChunkHandle(TheChunk));
   659 
   660 	test.Next(_L("Try changing restrictions"));
   661 	CHECK(KErrAccessDenied,==,TheChunk.SetRestrictions(0));
   662 
   663 	test.Next(_L("Check allocation restrictions"));
   664 	CHECK(KErrAccessDenied,==,TheChunk.Adjust(ChunkSize/2));
   665 	CHECK(KErrAccessDenied,==,TheChunk.AdjustDoubleEnded(PageSize,ChunkSize));
   666 	CHECK(KErrAccessDenied,==,TheChunk.Commit(PageSize,PageSize));
   667 	CHECK(KErrAccessDenied,==,TheChunk.Allocate(PageSize));
   668 	CHECK(KErrAccessDenied,==,TheChunk.Decommit(PageSize,PageSize));
   669 
   670 	test.Next(_L("Duplicate handle in same process"));
   671 	RChunk chunk2;
   672 	chunk2.SetHandle(TheChunk.Handle());
   673 	CHECK(KErrNone,==,chunk2.Duplicate(RThread(),EOwnerProcess));
   674 
   675 	test.Next(_L("Try passing handle to other process"));
   676 	if(aAttrib==EMultiple)
   677 		{
   678 		CHECK(0,==,CheckPlatSecPanic(HandleShare,*(TInt*)&chunk2));
   679 		}
   680 	else
   681 		{
   682 		CHECK(1,==,CheckPlatSecPanic(HandleShare,*(TInt*)&chunk2));
   683 		}
   684 	// Cleanup leftover process
   685 	OtherProcess.Kill(0);
   686 	OtherProcess.Close();
   687 
   688 	test.Next(_L("Close handles"));
   689 	chunk2.Close();
   690 	CHECK(0,==,Ldd.CloseChunk());
   691 	TheChunk.Close();
   692 
   693 	test.End();
   694 	}
   695 
   696 
   697 class TCommitRegion
   698 	{
   699 public:
   700 	TInt iOffset;
   701 	TInt iSize;
   702 	TInt iExpectedResult;
   703 	};
   704 
   705 void CheckRegion(TCommitRegion aRegion, TBool aCheckClear)
   706 	{
   707 	TUint8* Base = TheChunk.Base();
   708 	TInt offset = aRegion.iOffset*PageSize;
   709 	TInt limit = offset+aRegion.iSize*PageSize;
   710 	while(offset<limit)
   711 		{
   712 		KCHECK_MEMORY(1,offset);
   713 		UCHECK_MEMORY(1,offset);
   714 		offset += PageSize;
   715 		}
   716 	if(!aCheckClear)
   717 		return;
   718 
   719 	TUint32* ptr = (TUint32*)(Base+aRegion.iOffset*PageSize);
   720 	TUint32* end = (TUint32*)((TInt)ptr+aRegion.iSize*PageSize);
   721 	while(ptr<end)
   722 		if(*ptr++!=0x03030303u)
   723 			{
   724 			CHECK(0x03030303u,==,*ptr);
   725 			}
   726 	};
   727 
   728 void SetTags(TCommitRegion aRegion)
   729 	{
   730 	TUint8* Base = TheChunk.Base();
   731 	TInt offset = aRegion.iOffset*PageSize;
   732 	TInt limit = offset+aRegion.iSize*PageSize;
   733 	while(offset<limit)
   734 		{
   735 		*(TUint*)(Base+offset) = Tag(offset);
   736 		offset += sizeof(TUint);
   737 		}
   738 	};
   739 
   740 void CheckTags(const TCommitRegion& aRegion)
   741 	{
   742 	TUint8* Base = TheChunk.Base();
   743 	TInt offset = aRegion.iOffset*PageSize;
   744 	TInt limit = offset+aRegion.iSize*PageSize;
   745 	while(offset<limit)
   746 		{
   747 		KCHECK_MEMORY(1,offset);	// Check page exists
   748 		TInt limit2 = offset+PageSize;
   749 		while(offset<limit2)
   750 			{
   751 			UREAD_MEMORY(offset,Tag(offset));	// Check contents match tags we set previousely
   752 			offset += sizeof(TUint);
   753 			}
   754 		}
   755 	};
   756 
   757 void CheckOldTags(const TCommitRegion& aRegion, TInt aNewOffset)
   758 	{
   759 	TUint8* Base = TheChunk.Base();
   760 	TInt oldOffset = aRegion.iOffset*PageSize;
   761 	TInt offset = aNewOffset;
   762 	TInt limit = offset+aRegion.iSize*PageSize;
   763 	while(offset<limit)
   764 		{
   765 		KCHECK_MEMORY(1,offset);	// Check page exists
   766 		TInt limit2 = offset+PageSize;
   767 		while(offset<limit2)
   768 			{
   769 			UREAD_MEMORY(offset,Tag(oldOffset));	// Check contents matched old tags
   770 			offset += sizeof(TUint);
   771 			oldOffset += sizeof(TUint);
   772 			}
   773 		}
   774 	};
   775 
   776 // Following assumes 4k pages...
   777 static const TCommitRegion CommitList[] =
   778 	{
   779 		{0,0},		// zero size commit
   780 		{1,1},		// page 1
   781 
   782 		// Regions which overlap previous commit
   783 		{1,1,KErrAlreadyExists},
   784 		{0,2,KErrAlreadyExists},
   785 		{1,2,KErrAlreadyExists},
   786 		{0,3,KErrAlreadyExists},
   787 
   788 		{0,1},		// page 0
   789 		{2,1},		// page 2
   790 
   791 		{250,6},	// pages at end of chunk boundary
   792 
   793 		{768,256},	// whole 1meg chunk
   794 
   795 		{400,512,KErrAlreadyExists},	// Monster commit which overlaps previous regions
   796 
   797 		{256,257},	// big commit which straddles more than one 1meg chunk
   798 
   799 		{-1,-1} // End marker
   800 	};
   801 
   802 void CheckCommitedContents(TInt aIndex)
   803 	{
   804 	while(--aIndex>=0)
   805 		if(CommitList[aIndex].iExpectedResult==KErrNone)
   806 			CheckTags(CommitList[aIndex]);
   807 	};
   808 
   809 void CheckCommitState(TInt aIndex)
   810 	{
   811 	TInt page=0;
   812 	TInt lastPage=TheChunk.MaxSize()/PageSize;
   813 	while(page<lastPage)
   814 		{
   815 		TInt i=aIndex;
   816 		while(--i>=0)
   817 			if(CommitList[i].iExpectedResult==KErrNone)
   818 				if((TUint)(page-CommitList[i].iOffset) < (TUint)CommitList[i].iSize)
   819 					break;
   820 		TInt offset = page*PageSize;
   821 		if(i>=0)
   822 			{
   823 			KCHECK_MEMORY(1,offset);	// Check page exists
   824 			}
   825 		else
   826 			{
   827 			KCHECK_MEMORY(0,offset);	// Check page doesn't exists
   828 			}
   829 		++page;
   830 		}
   831 	};
   832 
   833 
   834 void TestCommit(TUint aCreateFlags,TCommitType aCommitType)
   835 	{
   836 	SetCreateFlags(aCreateFlags,aCommitType);
   837 	TUint ChunkAttribs = ChunkSize|aCreateFlags;
   838 
   839 	test.Start(_L("Create chunk"));
   840 	CHECK(KErrNone,==,Ldd.CreateChunk(ChunkAttribs));
   841 
   842 	test.Next(_L("Check wrong commit type"));
   843 	CHECK(KErrNotSupported,==,Ldd.CommitMemory((aCommitType^EPhysicalMask)|0,PageSize));
   844 	CHECK(KErrNotSupported,==,Ldd.CommitMemory((aCommitType^EPhysicalMask^EContiguous)|0,PageSize));
   845 
   846 	if((TInt)aCommitType&EPhysicalMask)
   847 		{
   848 		test.Next(_L("Check commit with bad pysical address"));
   849 		CHECK(KErrArgument,==,Ldd.CommitMemory((aCommitType|EBadPhysicalAddress)|0,PageSize));
   850 		}
   851 
   852 	test.Next(_L("Open user handle"));
   853 	CHECK(KErrNone,==,Ldd.GetChunkHandle(TheChunk));
   854 
   855 	const TCommitRegion* list = CommitList;
   856 	for(;list->iOffset>=0; ++list)
   857 		{
   858 		TInt offset = list->iOffset*PageSize;
   859 		TInt size = list->iSize*PageSize;
   860 		TInt expectedResult = list->iExpectedResult;
   861 		if((MemModelAttributes&EMemModelTypeMask)==EMemModelTypeDirect && expectedResult==KErrAlreadyExists)
   862 			continue;
   863 		TBuf<100> text;
   864 		text.AppendFormat(_L("Commit pages: offset=%08x size=%08x expectedResult=%d"),offset,size,expectedResult);
   865 		test.Next(text);
   866 
   867 		test.Start(_L("Do the Commit"));
   868 		CHECK(expectedResult,==,Ldd.CommitMemory(aCommitType|offset,size));
   869 
   870 		if(expectedResult==KErrNone)
   871 			{
   872 			test.Next(_L("Check new memory has been comitted"));
   873 			CheckRegion(*list,!(aCommitType&EPhysicalMask));
   874 			}
   875 
   876 		if((MemModelAttributes&EMemModelTypeMask)!=EMemModelTypeDirect)
   877 			{
   878 			test.Next(_L("Check commit state of all pages in chunk"));
   879 			CheckCommitState(list-CommitList+1);
   880 			}
   881 
   882 		test.Next(_L("Check contents of previous commited regions are unchanged"));
   883 		CheckCommitedContents(list-CommitList);
   884 
   885 		if(expectedResult==KErrNone)
   886 			{
   887 			test.Next(_L("Mark new memory"));
   888 			SetTags(*list);
   889 			}
   890 		test.End();
   891 		}
   892 
   893 	if((aCreateFlags&EMultiple) && (MemModelAttributes&EMemModelTypeMask)!=EMemModelTypeDirect)
   894 		{
   895 		test.Next(_L("Check another process sees same chunk state"));
   896 		TInt regionCount = list-CommitList;
   897 
   898 		// create another process
   899 		RProcess process;
   900 		CHECK(KErrNone,==,process.Create(KOtherProcessName,KNullDesC));
   901 		CHECK(KErrNone,==,process.SetParameter(1,ESlaveCheckChunk));
   902 		CHECK(KErrNone,==,process.SetParameter(2,(RBusLogicalChannel&)Ldd));
   903 		CHECK(KErrNone,==,process.SetParameter(3,(RChunk&)TheChunk));
   904 		CHECK(KErrNone,==,process.SetParameter(4,regionCount));
   905 		TRequestStatus status;
   906 		process.Logon(status);
   907 		process.Resume();
   908 
   909 		// Check chunk again in this process, concurrently with other process
   910 		CheckCommitedContents(regionCount);
   911 		CheckCommitState(regionCount);
   912 
   913 		// wait for other process to finish
   914 		User::WaitForRequest(status);
   915 		CHECK(EExitKill,==,process.ExitType());
   916 		CHECK(0,==,process.ExitReason());
   917 		CLOSE_AND_WAIT(process);
   918 		}
   919 
   920 	test.Next(_L("Close handles"));
   921 	TheChunk.Close();
   922 	CHECK(1,==,Ldd.CloseChunk());
   923 
   924 	if(aCommitType&EPhysicalMask)
   925 		{
   926 		// For Physical commit tests, check correct allocation by creating a new chunk
   927 		// and checking that pages comitted contain the old TAGs placed there by the
   928 		// tests above.
   929 
   930 		test.Next(_L("Check commit uses correct physical pages"));
   931 
   932 		test.Start(_L("Create chunk"));
   933 		CHECK(KErrNone,==,Ldd.CreateChunk(ChunkAttribs));
   934 
   935 		test.Next(_L("Open user handle"));
   936 		CHECK(KErrNone,==,Ldd.GetChunkHandle(TheChunk));
   937 
   938 		TInt offset = 0;
   939 		for(list=CommitList; list->iOffset>=0; ++list)
   940 			{
   941 			if(list->iExpectedResult!=KErrNone)
   942 				continue;
   943 
   944 			TInt size = list->iSize*PageSize;
   945 			TBuf<100> text;
   946 			text.AppendFormat(_L("Commit pages: offset=%08x size=%08x"),offset,size);
   947 			test.Next(text);
   948 			CHECK(KErrNone,==,Ldd.CommitMemory(aCommitType|offset,size));
   949 
   950 			test.Next(_L("Check RAM contents preserved from previous usage"));
   951 			CheckOldTags(*list,offset);
   952 			offset += size;
   953 			}
   954 
   955 		test.Next(_L("Close handles"));
   956 		TheChunk.Close();
   957 		CHECK(1,==,Ldd.CloseChunk());
   958 
   959 		test.End();
   960 		}
   961 	else
   962 		{
   963 		// We don't do these OOM tests for Physical commit because we can't do it reliably
   964 		// (as only a couple of page tables come from the free pool not the whole memory
   965 		// to be comitted)
   966 		test.Next(_L("Check Out Of Memory conditions"));
   967 
   968 		// Make sure any clean up has happened otherwise the amount of free RAM may change.
   969 		UserSvr::HalFunction(EHalGroupKernel, EKernelHalSupervisorBarrier, 0, 0);
   970 
   971 		test.Start(_L("Gobble up most of RAM"));
   972 		test.Next(_L("Load gobbler LDD"));
   973 		TInt r = User::LoadLogicalDevice(KGobblerLddFileName);
   974 		test(r==KErrNone || r==KErrAlreadyExists);
   975 		RGobbler gobbler;
   976 		r = gobbler.Open();
   977 		test(r==KErrNone);
   978 		TUint32 taken = gobbler.GobbleRAM(2*1024*1024);
   979 		test.Printf(_L("Gobbled: %dK\n"), taken/1024);
   980 		test.Printf(_L("Free RAM 0x%08X bytes\n"),FreeRam());
   981 
   982 		test.Next(_L("Get baseline free memory"));
   983 		__KHEAP_MARK;
   984 		TInt freeRam1 = FreeRam();
   985 
   986 		test.Next(_L("Create shared chunk"));
   987 		CHECK(KErrNone,==,Ldd.CreateChunk(ChunkAttribs));
   988 		TInt freeRam2 = FreeRam();
   989 
   990 		test.Next(_L("Commit memory which will causes OOM"));
   991 		CHECK(KErrNoMemory,==,Ldd.CommitMemory(aCommitType,4096*1024));
   992 
   993 		test.Next(_L("Check free RAM unchanged"));
   994 		CHECK(freeRam2,==,FreeRam());
   995 
   996 		test.Next(_L("Check OOM during ChunkCommit"));
   997 		TInt failResult=KErrGeneral;
   998 		for(TInt failCount=1; failCount<1000; failCount++)
   999 			{
  1000 			User::__DbgSetAllocFail(ETrue,RAllocator::EFailNext,failCount);
  1001 			failResult = Ldd.CommitMemory(aCommitType,1);
  1002 			if(failResult==KErrNone)
  1003 				break;
  1004 			CHECK(KErrNoMemory,==,failResult);
  1005 			}
  1006 		User::__DbgSetAllocFail(ETrue,RAllocator::ENone,0);
  1007 		CHECK(KErrNone,==,failResult);
  1008 
  1009 		test.Next(_L("Destroy shared chunk"));
  1010 		CHECK(1,==,Ldd.CloseChunk());
  1011 		CHECK(1,==,Ldd.IsDestroyed());
  1012 
  1013 		test.Next(_L("Check free memory returns to baseline"));
  1014 		CHECK(freeRam1,==,FreeRam());
  1015 		__KHEAP_MARKEND;
  1016 
  1017 		test.Next(_L("Free gobbled RAM"));
  1018 		gobbler.Close();
  1019 
  1020 		test.End();
  1021 		}
  1022 
  1023 	test.End();
  1024 	}
  1025 
  1026 
  1027 void TestOpenSharedChunk(TUint aCreateFlags,TCommitType aCommitType)
  1028 	{
  1029 	SetCreateFlags(aCreateFlags,aCommitType);
  1030 	TUint ChunkAttribs = ChunkSize|aCreateFlags;
  1031 
  1032 	test.Start(_L("Create chunk"));
  1033 	CHECK(KErrNone,==,Ldd.CreateChunk(ChunkAttribs));
  1034 
  1035 	test.Next(_L("Open user handle"));
  1036 	CHECK(KErrNone,==,Ldd.GetChunkHandle(TheChunk));
  1037 
  1038 	test.Next(_L("Commit some memory"));
  1039 	CHECK(KErrNone,==,Ldd.CommitMemory(aCommitType|1*PageSize,PageSize));
  1040 	CHECK(KErrNone,==,Ldd.CommitMemory(aCommitType|2*PageSize,PageSize));
  1041 	CHECK(KErrNone,==,Ldd.CommitMemory(aCommitType|4*PageSize,PageSize));
  1042 
  1043 	test.Next(_L("Check OpenSharedChunk with handle"));
  1044 	CHECK(KErrNone,==,Ldd.TestOpenHandle(TheChunk.Handle()));
  1045 
  1046 	test.Next(_L("Check OpenSharedChunk with wrong chunk handle"));
  1047 	RChunk testChunk;
  1048 	CHECK(KErrNone,==,testChunk.CreateLocal(PageSize,PageSize));
  1049 	CHECK(KErrNotFound,==,Ldd.TestOpenHandle(testChunk.Handle()));
  1050 	testChunk.Close();
  1051 
  1052 	test.Next(_L("Check OpenSharedChunk with wrong handle type"));
  1053 	CHECK(KErrNotFound,==,Ldd.TestOpenHandle(RThread().Handle()));
  1054 
  1055 	test.Next(_L("Check OpenSharedChunk with bad handle"));
  1056 	CHECK(KErrNotFound,==,Ldd.TestOpenHandle(0));
  1057 
  1058 	test.Next(_L("Check OpenSharedChunk with address"));
  1059 	TUint8* Base = TheChunk.Base();
  1060 	CHECK(KErrNone,==,Ldd.TestOpenAddress(Base));
  1061 	CHECK(KErrNone,==,Ldd.TestOpenAddress(Base+ChunkSize-1));
  1062 
  1063 	test.Next(_L("Check OpenSharedChunk with bad address"));
  1064 	CHECK(KErrNotFound,==,Ldd.TestOpenAddress(Base-1));
  1065 	CHECK(KErrNotFound,==,Ldd.TestOpenAddress(Base+ChunkSize));
  1066 	CHECK(KErrNotFound,==,Ldd.TestOpenAddress(0));
  1067 	CHECK(KErrNotFound,==,Ldd.TestOpenAddress((TAny*)~0));
  1068 
  1069 	test.Next(_L("Check OpenSharedChunk with stack memory address"));
  1070 	TUint8 stackMem[100];
  1071 	CHECK(KErrNotFound,==,Ldd.TestOpenAddress(stackMem));
  1072 
  1073 	test.Next(_L("Check OpenSharedChunk with heap memory address"));
  1074 	TUint8* heapMem = new TUint8[100];
  1075 	CHECK(0,!=,heapMem);
  1076 	CHECK(KErrNotFound,==,Ldd.TestOpenAddress(heapMem));
  1077 	delete [] heapMem;
  1078 
  1079 	test.Next(_L("Check OpenSharedChunk with BSS memory address"));
  1080 	CHECK(KErrNotFound,==,Ldd.TestOpenAddress(BssMem));
  1081 
  1082 	test.Next(_L("Check OpenSharedChunk with code memory address"));
  1083 	CHECK(KErrNotFound,==,Ldd.TestOpenAddress((TAny*)&TestOpenSharedChunk));
  1084 
  1085 	test.Next(_L("Check OpenSharedChunk with NULL address"));
  1086 	CHECK(KErrNotFound,==,Ldd.TestOpenAddress(0));
  1087 
  1088 	test.Next(_L("Check ChunkAddress for given memory region"));
  1089 	static const TCommitRegion regions[] = 
  1090 		{
  1091 			{0,1,KErrNotFound},
  1092 			{0,2,KErrNotFound},
  1093 			{0,3,KErrNotFound},
  1094 			{1,1},
  1095 			{1,2},
  1096 			{1,3,KErrNotFound},
  1097 			{2,1},
  1098 			{2,2,KErrNotFound},
  1099 			{2,3,KErrNotFound},
  1100 			{3,1,KErrNotFound},
  1101 			{3,2,KErrNotFound},
  1102 			{3,3,KErrNotFound},
  1103 			{4,1},
  1104 			{4,2,KErrNotFound},
  1105 			{4,3,KErrNotFound},
  1106 			{0,10240,KErrArgument}, // too big
  1107 			{1,0,KErrArgument}, // bad size
  1108 			{1,-1,KErrArgument}, // bad size
  1109 			{10240,1,KErrArgument}, // bad offset
  1110 			{-2,2,KErrArgument}, // bad offset
  1111 			{-1}
  1112 		};
  1113 	const TCommitRegion* region = regions;
  1114 	for(;region->iOffset!=-1; ++region)
  1115 		{
  1116 		TUint32 offset = region->iOffset*PageSize;
  1117 		TUint32 size = region->iSize*PageSize;
  1118 		TInt expectedResult = region->iExpectedResult;
  1119 		if((MemModelAttributes&EMemModelTypeMask)==EMemModelTypeDirect && expectedResult==KErrNotFound)
  1120 			continue;
  1121 		TBuf<100> text;
  1122 		text.AppendFormat(_L("Memory region: offset=%08x size=%08x expectedResult=%d"),offset,size,expectedResult);
  1123 		test.Next(text);
  1124 		CHECK(expectedResult,==,Ldd.TestAddress(offset,size));
  1125 		}
  1126 
  1127 	test.Next(_L("Close handles"));
  1128 	TheChunk.Close();
  1129 	CHECK(1,==,Ldd.CloseChunk());
  1130 
  1131 	test.End();
  1132 	}
  1133 
  1134 
  1135 void AccessSpeed(TCreateFlags aCreateFlags, TInt& aRead,TInt& aWrite)
  1136 	{
  1137 //	test.Start(_L("Create chunk"));
  1138 	CHECK(KErrNone,==,Ldd.CreateChunk(ChunkSize|ESingle|EOwnsMemory|aCreateFlags));
  1139 
  1140 //	test.Next(_L("Commit some memory"));
  1141 	if((MemModelAttributes&EMemModelTypeMask)==EMemModelTypeDirect)
  1142 		{
  1143 		CHECK(KErrNone,==,Ldd.CommitMemory(EDiscontiguous|0*PageSize,PageSize));
  1144 		}
  1145 	else
  1146 		{
  1147 		// Allocate contiguous memory when possible so that the
  1148 		// Cache::SyncMemoryBeforeXxxx calls in the test driver get exercised
  1149 		CHECK(KErrNone,==,Ldd.CommitMemory(EContiguous|0*PageSize,PageSize));
  1150 		}
  1151 
  1152 //	test.Next(_L("Open user handle"));
  1153 	CHECK(KErrNone,==,Ldd.GetChunkHandle(TheChunk));
  1154 	volatile TUint32* p = (TUint32*)TheChunk.Base();
  1155 
  1156 	TUint32 time;
  1157 	TInt itterCount=128;
  1158 	do
  1159 		{
  1160 		itterCount *= 2;
  1161 		TUint32 lastCount=User::NTickCount();
  1162 		for(TInt i=itterCount; i>0; --i)
  1163 			{
  1164 			TUint32 x=p[0]; x=p[1]; x=p[2]; x=p[3]; x=p[4]; x=p[5]; x=p[6]; x=p[7];
  1165 			}
  1166 		time = User::NTickCount()-lastCount;
  1167 		}
  1168 	while(time<200);
  1169 	aRead = itterCount*8/time;
  1170 
  1171 	itterCount=128;
  1172 	do
  1173 		{
  1174 		itterCount *= 2;
  1175 		TUint32 lastCount=User::NTickCount();
  1176 		for(TInt i=itterCount; i>0; --i)
  1177 			{
  1178 			p[0]=i; p[1]=i; p[2]=i; p[3]=i; p[4]=i; p[5]=i; p[6]=i; p[7]=i;
  1179 			}
  1180 		time = User::NTickCount()-lastCount;
  1181 		}
  1182 	while(time<200);
  1183 	aWrite = itterCount*8/time;
  1184 
  1185 	TBuf<100> text;
  1186 	text.AppendFormat(_L("Read speed=%7d    Write speed=%7d\n"),aRead,aWrite);
  1187 	test.Printf(text);
  1188 
  1189 //	test.Next(_L("Close handles"));
  1190 	TheChunk.Close();
  1191 	CHECK(1,==,Ldd.CloseChunk());
  1192 
  1193 //	test.End();
  1194 	}
  1195 
  1196 void TestMappingAttributes()
  1197 	{
  1198 	test.Start(_L("Fully Blocking"));
  1199 	TInt blockedRead;
  1200 	TInt blockedWrite;
  1201 	AccessSpeed(EBlocking,blockedRead,blockedWrite);
  1202 
  1203 	TInt read;
  1204 	TInt write;
  1205 
  1206 	test.Next(_L("Write Buffered"));
  1207 	AccessSpeed(EBuffered,read,write);
  1208 	CHECK(2*blockedRead,>,read);
  1209 //	CHECK(2*blockedWrite,<,write);  // Write buffering doesn't seem to work when cache disabled (?)
  1210 
  1211 	test.Next(_L("Fully Cached"));
  1212 	AccessSpeed(ECached,read,write);
  1213 	CHECK(2*blockedRead,<,read);
  1214 #ifndef __X86__	// X86 seems to do always do write buffering
  1215 	// Following check disabled because most dev boards only seem to be a bit faster
  1216 	// and asserting a particular speed improvement is unreliable
  1217 //	CHECK(2*blockedWrite,<,write);
  1218 #endif
  1219 
  1220 	test.End();
  1221 	}
  1222 
  1223 class RSession : public RSessionBase
  1224 	{
  1225 public:
  1226 	inline TInt CreateSession(const TDesC& aServer,const TVersion& aVersion)
  1227 		{ return RSessionBase::CreateSession(aServer,aVersion); }
  1228 	inline TInt SendReceive(TInt aFunction,const TIpcArgs& aArgs) const
  1229 		{ return RSessionBase::SendReceive(aFunction,aArgs); }
  1230 	};
  1231 
  1232 TInt SlaveCommand(TSlaveCommand aCommand)
  1233 	{
  1234 	RDebug::Print(_L("Slave Process - Command %d\n"),aCommand);
  1235 	CHECK(KErrNone,==,UserHal::PageSizeInBytes(PageSize));
  1236 	CHECK(KErrNone,==,((RBusLogicalChannel&)Ldd).Open(2,EOwnerProcess));
  1237 	switch(aCommand)
  1238 		{
  1239 	case ESlaveCheckChunk:
  1240 		{
  1241 		RDebug::Print(_L("Slave Process - TheChunk.Open()\n"));
  1242 		CHECK(KErrNone,==,TheChunk.Open(3));
  1243 		RDebug::Print(_L("Slave Process - Get Region Count\n"));
  1244 		TInt regionCount;
  1245 		CHECK(KErrNone,==,User::GetTIntParameter(4,regionCount));
  1246 		RDebug::Print(_L("Slave Process - CheckCommitedContents(%d)\n"),regionCount);
  1247 		CheckCommitedContents(regionCount);
  1248 		RDebug::Print(_L("Slave Process - CheckCommitState(%d)\n"),regionCount);
  1249 		CheckCommitState(regionCount);
  1250 		RDebug::Print(_L("Slave Process - Done\n"));
  1251 		return 0;
  1252 		}
  1253 
  1254 	case ESlaveCreateChunk:
  1255 		{
  1256 		RDebug::Print(_L("Slave Process - Get parameters\n"));
  1257 		TInt createFlags;
  1258 		TInt commitType;
  1259 		TInt commitSize;
  1260 		CHECK(KErrNone,==,User::GetTIntParameter(3,createFlags));
  1261 		CHECK(KErrNone,==,User::GetTIntParameter(4,commitType));
  1262 		CHECK(KErrNone,==,User::GetTIntParameter(5,commitSize));
  1263 
  1264 		RDebug::Print(_L("Slave Process - Create Chunk\n"));
  1265 		CHECK(KErrNone,==,Ldd.CreateChunk(createFlags));
  1266 		CHECK(KErrNone,==,Ldd.CommitMemory(commitType,commitSize));
  1267 		CHECK(KErrNone,==,Ldd.GetChunkHandle(TheChunk));
  1268 		TUint8* chunkBase=TheChunk.Base();
  1269 		memcpy(chunkBase,KTestString().Ptr(),KTestString().Size());
  1270 
  1271 		RDebug::Print(_L("Slave Process - Connecting to test server\n"));
  1272 		RSession session;
  1273 		CHECK(KErrNone,==,session.CreateSession(KSecondProcessName,TVersion()));
  1274 
  1275 		RDebug::Print(_L("Slave Process - Sending message\n"));
  1276 		TPtr8 ptr(chunkBase,commitSize,commitSize);
  1277 		session.SendReceive(0,TIpcArgs(&ptr));
  1278 
  1279 		RDebug::Print(_L("Slave Process - Destroy Chunk\n"));
  1280 		TheChunk.Close();
  1281 		CHECK(1,==,Ldd.CloseChunk()); // 1==DObject::EObjectDeleted
  1282 		CHECK(1,==,Ldd.IsDestroyed());
  1283 		return 0;
  1284 		}
  1285 
  1286 	default:
  1287 		RDebug::Print(_L("Slave Process - Bad Command\n"));
  1288 		return KErrArgument;
  1289 		}
  1290 	}
  1291 
  1292 void TestChunkUserBase()
  1293 	{
  1294 	TUint ChunkAttribs = ChunkSize|ESingle|EOwnsMemory;
  1295 
  1296 	test.Start(_L("Create chunk"));
  1297 	CHECK(KErrNone,==,Ldd.CreateChunk(ChunkAttribs));
  1298 
  1299 	test.Next(_L("Open user handle"));
  1300 	CHECK(KErrNone,==,Ldd.GetChunkHandle(TheChunk));
  1301 
  1302 	test.Next(_L("Commit some memory"));
  1303 	CHECK(KErrNone,==,Ldd.CommitMemory(EDiscontiguous|1*PageSize,PageSize));
  1304 
  1305 	test.Next(_L("Check OpenSharedChunk with handle"));
  1306 	CHECK(KErrNone,==,Ldd.TestOpenHandle(TheChunk.Handle()));
  1307 
  1308 	test.Next(_L("Get Kernel's user base"));
  1309 	TAny *kernelUserAddress;
  1310 	CHECK(KErrNone,==,Ldd.GetChunkUserBase(&kernelUserAddress));
  1311 	TAny *userAddress = TheChunk.Base();
  1312 	test(kernelUserAddress == userAddress);
  1313 	
  1314 	TheChunk.Close();
  1315 	CHECK(1,==,Ldd.CloseChunk());
  1316 
  1317 	test.End();
  1318 	}
  1319 
  1320 
  1321 TInt E32Main()
  1322 	{
  1323 	// Running as slave?
  1324 	TInt slaveCommand;
  1325 	if(User::GetTIntParameter(1,slaveCommand)==KErrNone)
  1326 		return SlaveCommand((TSlaveCommand)slaveCommand);
  1327 
  1328 // Turn off lazy dll unloading
  1329 	RLoader l;
  1330 	test(l.Connect()==KErrNone);
  1331 	test(l.CancelLazyDllUnload()==KErrNone);
  1332 	l.Close();
  1333 
  1334 	test.Title();
  1335 
  1336 	MemModelAttributes=UserSvr::HalFunction(EHalGroupKernel, EKernelHalMemModelInfo, NULL, NULL);
  1337 	TUint mm=MemModelAttributes&EMemModelTypeMask;
  1338 #ifdef __T_SHAREDCHUNKF__
  1339 	if(mm!=EMemModelTypeMoving)
  1340 		{
  1341 		test.Start(_L("TESTS NOT RUN - Only valid on Moving Memory Model"));
  1342 		test.End();
  1343 		return 0;
  1344 		}
  1345 #endif
  1346 
  1347 	test.Start(_L("Initialise"));
  1348 	CHECK(KErrNone,==,UserHal::PageSizeInBytes(PageSize));
  1349 	PhysicalCommitSupported = mm!=EMemModelTypeDirect && mm!=EMemModelTypeEmul;
  1350 	CachingAttributesSupported = mm!=EMemModelTypeDirect && mm!=EMemModelTypeEmul;
  1351 
  1352 
  1353 	test.Next(_L("Loading test driver"));
  1354 	TInt r = User::LoadLogicalDevice(KSharedChunkLddName);
  1355 	test(r==KErrNone || r==KErrAlreadyExists);
  1356 
  1357 	test.Next(_L("Opening channel"));
  1358 	CHECK(KErrNone,==,Ldd.Open());
  1359 
  1360 	// now 'unload' test driver, however, it will remain loaded whilst
  1361 	// we still have a channel open with it... 
  1362 	User::FreeLogicalDevice(KSharedChunkLddName);
  1363 
  1364 	test.Next(_L("Test chunk create"));
  1365 	TestCreate();
  1366 
  1367 	test.Next(_L("Test handles"));
  1368 	TestHandles();
  1369 
  1370 	test.Next(_L("Test handle ownership"));
  1371 	TestHandleOwnership();
  1372 
  1373 	test.Next(_L("Test restrictions for multiply shared chunks"));
  1374 	TestRestrictions(EMultiple);
  1375 	test.Next(_L("Test restrictions for singly shared chunks"));
  1376 	TestRestrictions(ESingle);
  1377 
  1378 	test.Next(_L("Test memory access for multiply shared chunks"));
  1379 	TestAccess(EMultiple|EOwnsMemory,EDiscontiguous);
  1380 	test.Next(_L("Test memory access for singly shared chunks"));
  1381 	TestAccess(ESingle|EOwnsMemory,EDiscontiguous);
  1382 
  1383 	test.Next(_L("Test Discontiguous memory commit for multiply shared chunks"));
  1384 	TestCommit(EMultiple,EDiscontiguous);
  1385 	test.Next(_L("Test Discontiguous memory commit for singly shared chunks"));
  1386 	TestCommit(ESingle,EDiscontiguous);
  1387 
  1388 	if((MemModelAttributes&EMemModelTypeMask)!=EMemModelTypeDirect)
  1389 		{
  1390 		test.Next(_L("Test Contiguous memory commit for multiply shared chunks"));
  1391 		TestCommit(EMultiple,EContiguous);
  1392 		test.Next(_L("Test Contiguous memory commit for singly shared chunks"));
  1393 		TestCommit(ESingle,EContiguous);
  1394 		}
  1395 
  1396 	if(PhysicalCommitSupported)
  1397 		{
  1398 		test.Next(_L("Test Discontiguous Physical commit for multiply shared chunks"));
  1399 		TestCommit(EMultiple,EDiscontiguousPhysical);
  1400 		test.Next(_L("Test Discontiguous Physical commit for singly shared chunks"));
  1401 		TestCommit(ESingle,EDiscontiguousPhysical);
  1402 
  1403 		test.Next(_L("Test Contiguous Physical commit for multiply shared chunks"));
  1404 		TestCommit(EMultiple,EContiguousPhysical);
  1405 		test.Next(_L("Test Contiguous Physical commit for singly shared chunks"));
  1406 		TestCommit(ESingle,EContiguousPhysical);
  1407 		}
  1408 
  1409 	test.Next(_L("Test Kern::OpenSharedChunk for multiply shared chunks"));
  1410 	TestOpenSharedChunk(EMultiple,EDiscontiguous);
  1411 	test.Next(_L("Test Kern::OpenSharedChunk for singly shared chunks"));
  1412 	TestOpenSharedChunk(ESingle,EDiscontiguous);
  1413 
  1414 	if(CachingAttributesSupported)
  1415 		{
  1416 		test.Next(_L("Test Mapping Attributes"));
  1417 		TestMappingAttributes();
  1418 		}
  1419 	
  1420 	test.Next(_L("Testing Kern::ChunkUserBase for shared chunks"));
  1421 	TestChunkUserBase();
  1422 
  1423 	if (PhysicalCommitSupported)
  1424 		{
  1425 		test.Next(_L("Testing Kern::ChunkClose allows immediate freeing of physical ram"));
  1426 		test_KErrNone(Ldd.TestChunkCloseAndFree());
  1427 		}
  1428 
  1429 	test.Next(_L("Close test driver"));
  1430 	Ldd.Close();
  1431 
  1432 	test.End();
  1433 
  1434 	return 0;
  1435 	}