kerneltest/e32test/debug/d_context.cpp
changeset 0 a41df078684a
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     1 // Copyright (c) 2003-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\debug\d_context.cpp
       
    15 // Test LDD exercising hardware/software exception hooks 
       
    16 // and get/set user context APIs.
       
    17 // 
       
    18 //
       
    19 
       
    20 #include "platform.h"
       
    21 #include <kernel/kern_priv.h>
       
    22 #include "kern_test.h"
       
    23 #include "d_context.h"
       
    24 
       
    25 _LIT(KClientPanicCat, "D_CONTEXT");
       
    26 
       
    27 extern TUint32 SpinInKernel(TBool);
       
    28 
       
    29 DThread* ThreadFromId(TUint aId)
       
    30 	{
       
    31 	// This is risky because the thread could die on us an the DThread* become invalid.
       
    32 	// We are relying on this never happening in our test code.
       
    33 	NKern::ThreadEnterCS(); 
       
    34 	DObjectCon& threads=*Kern::Containers()[EThread];
       
    35 	threads.Wait(); 
       
    36 	DThread* thread = Kern::ThreadFromId(aId);
       
    37 	threads.Signal();
       
    38 	NKern::ThreadLeaveCS(); 
       
    39 	return thread;
       
    40 	}
       
    41 
       
    42 void ModifyContext(TArmRegSet& aContext)
       
    43 	{
       
    44 	TArmReg* end = (TArmReg*)(&aContext+1);
       
    45 	for (TArmReg* p = (TArmReg*)&aContext; p<end; ++p)
       
    46 		*p = ~*p;
       
    47 	}
       
    48 
       
    49 void DumpContext(TArmRegSet& aContext)
       
    50 	{
       
    51 	Kern::Printf("  r0 =%08x r1 =%08x r2 =%08x r3 =%08x",aContext.iR0,aContext.iR1,aContext.iR2,aContext.iR3);
       
    52 	Kern::Printf("  r4 =%08x r5 =%08x r6 =%08x r7 =%08x",aContext.iR4,aContext.iR5,aContext.iR6,aContext.iR7);
       
    53 	Kern::Printf("  r8 =%08x r9 =%08x r10=%08x r11=%08x",aContext.iR8,aContext.iR9,aContext.iR10,aContext.iR11);
       
    54 	Kern::Printf("  r12=%08x r13=%08x r14=%08x r15=%08x",aContext.iR12,aContext.iR13,aContext.iR14,aContext.iR15);
       
    55 	Kern::Printf("  cpsr=%08x dacr=%08x",aContext.iFlags, aContext.iDacr);
       
    56 	}
       
    57 
       
    58 inline TBool IsRegisterAvailable(TInt aReg, TUint32 aMask)
       
    59 	{
       
    60 	return aMask & (1<<aReg);
       
    61 	}
       
    62 
       
    63 TInt CheckSetContext(const TArmRegSet& aSetContext, const TArmRegSet& aContextAfterSet, TUint32 aAvailMask)
       
    64 	{
       
    65 	Kern::Printf("Checking all available registers have been modified (0%08x)", aAvailMask);
       
    66 
       
    67 	const TArmReg* pSet = (const TArmReg*)&aSetContext;
       
    68 	const TArmReg* pAfterSet = (const TArmReg*)&aContextAfterSet;
       
    69 
       
    70 	for (int i=0; i<=EArmPc; ++i)
       
    71 		{
       
    72 		if (pAfterSet[i] == 0 && IsRegisterAvailable(i, aAvailMask) && pSet[i] != 0)
       
    73 			{
       
    74 			Kern::Printf("Register %d not set (expected %08x actual %08x)", i, pSet[i], pAfterSet[i]);
       
    75 			return KErrCorrupt;
       
    76 			}
       
    77 		if (pAfterSet[i] != 0 && ! IsRegisterAvailable(i, aAvailMask))
       
    78 			{
       
    79 			Kern::Printf("Register %d incorrectly set (expected %08x actual %08x)", i, 0, pAfterSet[i]);
       
    80 			return KErrCorrupt;
       
    81 			}
       
    82 		}
       
    83 
       
    84 	return KErrNone;
       
    85 	}
       
    86 
       
    87 //////////////////////////////////////////////////////////////////////////////
       
    88 
       
    89 class DEventHandler : public DKernelEventHandler
       
    90 	{
       
    91 public:
       
    92 	DEventHandler();
       
    93 	TInt Create(DLogicalDevice* aDevice);
       
    94 	~DEventHandler();
       
    95 	void Cancel();
       
    96 private:
       
    97 	static TUint EventHandler(TKernelEvent aEvent, TAny* a1, TAny* a2, TAny* aThis);
       
    98 	TUint HandleEvent(TKernelEvent aType, TAny* a1, TAny* a2);
       
    99 	TBool HandleException(TRequestStatus*& aStatusPtr, TClientRequest*& aRequestPtr);
       
   100 	void HandleThreadDeath();
       
   101 	void Cleanup();
       
   102 private:
       
   103 	DThread* iClientThread;
       
   104 	DMutex* iLock; // serialise calls to handler
       
   105 public:
       
   106 	DLogicalDevice* iDevice;	// open reference to LDD for avoiding lifetime issues
       
   107 	// software exception fields
       
   108 	TExcType iSwExcLastType;
       
   109 	TInt* iSwExcCounterPtr;
       
   110 	TRequestStatus* iSwExcStatusPtr;
       
   111 	TClientRequest* iClientRequestSwExc;
       
   112 	// hardware exception fields
       
   113 	TRequestStatus* iHwExcStatusPtr;
       
   114 	TClientRequest* iClientRequestHwExc;
       
   115 	// fields used for both hardware and software exceptions
       
   116 	TUint iExcThreadId;
       
   117 	TAny* iExcContextPtr;
       
   118 	TBool iExcKillThread;
       
   119 	// thread death event fields
       
   120 	TUint iDeathThreadId;
       
   121 	TRequestStatus* iDeathStatusPtr;
       
   122 	TAny* iDeathContextPtr;
       
   123 	TClientRequest* iClientRequestDeath;
       
   124 	};
       
   125 
       
   126 
       
   127 DEventHandler::DEventHandler() 
       
   128 	: 	DKernelEventHandler(EventHandler, this) 
       
   129 	{
       
   130 	}
       
   131 
       
   132 
       
   133 TInt DEventHandler::Create(DLogicalDevice* aDevice)
       
   134 	{
       
   135 	TInt r;
       
   136 	r = aDevice->Open();
       
   137 	if (r != KErrNone)
       
   138 		goto error;
       
   139 	iDevice = aDevice;
       
   140 	iClientThread = &Kern::CurrentThread();
       
   141 	r = Kern::CreateClientRequest(iClientRequestSwExc);
       
   142 	if (r != KErrNone)
       
   143 		goto error;
       
   144 	r = Kern::CreateClientRequest(iClientRequestHwExc);
       
   145 	if (r != KErrNone)
       
   146 		goto error;
       
   147 	r = Kern::CreateClientRequest(iClientRequestDeath);
       
   148 	if (r != KErrNone)
       
   149 		goto error;
       
   150 	r = Kern::MutexCreate(iLock, _L("EventHandlerLock"), KMutexOrdDebug);
       
   151 	if (r != KErrNone)
       
   152 		goto error;
       
   153 	return Add();
       
   154 error:
       
   155 	Cleanup();
       
   156 	return r;
       
   157 	}
       
   158 
       
   159 void DEventHandler::Cleanup()
       
   160 	{
       
   161 	if (iLock)
       
   162 		iLock->Close(NULL);
       
   163 	if (iDevice)
       
   164 		iDevice->Close(NULL);
       
   165 	if (iClientRequestSwExc)
       
   166 		{
       
   167 		Kern::DestroyClientRequest(iClientRequestSwExc);
       
   168 		iClientRequestSwExc = NULL;
       
   169 		}
       
   170 	if (iClientRequestHwExc)
       
   171 		{
       
   172 		Kern::DestroyClientRequest(iClientRequestHwExc);
       
   173 		iClientRequestHwExc = NULL;
       
   174 		}
       
   175 	if (iClientRequestDeath)
       
   176 		{
       
   177 		Kern::DestroyClientRequest(iClientRequestDeath);
       
   178 		iClientRequestDeath = NULL;
       
   179 		}
       
   180 	}
       
   181 
       
   182 DEventHandler::~DEventHandler()
       
   183 	{
       
   184 	Cleanup();
       
   185 	}
       
   186 
       
   187 
       
   188 void DEventHandler::Cancel()
       
   189 	{
       
   190 	Kern::MutexWait(*iLock);
       
   191 	if (iHwExcStatusPtr)
       
   192 		{
       
   193 		Kern::QueueRequestComplete(iClientThread, iClientRequestHwExc, KErrCancel);
       
   194 		iHwExcStatusPtr = NULL;
       
   195 		}
       
   196 	if (iSwExcStatusPtr)
       
   197 		{
       
   198 		Kern::QueueRequestComplete(iClientThread, iClientRequestSwExc, KErrCancel);
       
   199 		iSwExcStatusPtr = NULL;
       
   200 		}
       
   201 	Kern::MutexSignal(*iLock);
       
   202 	}
       
   203 
       
   204 
       
   205 TUint DEventHandler::EventHandler(TKernelEvent aEvent, TAny* a1, TAny* a2, TAny* aThis)
       
   206 	{
       
   207 	return ((DEventHandler*)aThis)->HandleEvent(aEvent, a1, a2);
       
   208 	}
       
   209 
       
   210 
       
   211 // called in thread CS
       
   212 TUint DEventHandler::HandleEvent(TKernelEvent aType, TAny* a1, TAny* a2)
       
   213 	{
       
   214 	// Ensure handler always called in thread critical section
       
   215 	NThread& nt = Kern::CurrentThread().iNThread;
       
   216 	__ASSERT_ALWAYS(nt.iCsCount != 0, (NKern::Lock(),*(TInt*)0xfaece5=0));
       
   217 
       
   218 	TUint r = DKernelEventHandler::ERunNext;
       
   219 
       
   220 	switch (aType)
       
   221 		{
       
   222 	case EEventSwExc:
       
   223 		// HACK, EVIL UNSAFE MEMORY ACCESS FOLLOWS...
       
   224 		TInt counter;
       
   225 		// folowing will kill system if memory is bad (because we're in a critical section)
       
   226 		umemget32(&counter, iSwExcCounterPtr, sizeof(TInt*));
       
   227 		++counter;
       
   228 		umemput32(iSwExcCounterPtr, &counter, sizeof(TInt));
       
   229 
       
   230 		Kern::MutexWait(*iLock);
       
   231 		iSwExcLastType = (TExcType)(TInt)a1;
       
   232 		if (iSwExcStatusPtr)
       
   233 			HandleException(iSwExcStatusPtr, iClientRequestSwExc);
       
   234 		Kern::MutexSignal(*iLock);
       
   235 		break;
       
   236 	case EEventHwExc:
       
   237 		Kern::MutexWait(*iLock);
       
   238 		if (iHwExcStatusPtr)
       
   239 			if (HandleException(iHwExcStatusPtr, iClientRequestHwExc))
       
   240 				r |= (TUint)EExcHandled;
       
   241 		Kern::MutexSignal(*iLock);
       
   242 		break;
       
   243 	case EEventKillThread:
       
   244 		Kern::MutexWait(*iLock);
       
   245 		HandleThreadDeath();
       
   246 		Kern::MutexSignal(*iLock);
       
   247 		break;
       
   248 	default:
       
   249 		// NO-OP
       
   250 		break;
       
   251 		}
       
   252 	
       
   253 	return r;
       
   254 	}
       
   255 
       
   256 
       
   257 // called in thread CS
       
   258 TBool DEventHandler::HandleException(TRequestStatus*& aStatusPtr, TClientRequest*& aRequestPtr)
       
   259 	{
       
   260 	DThread& t = Kern::CurrentThread();
       
   261 	TBool handled = EFalse;
       
   262 
       
   263 	if (iExcThreadId == t.iId)
       
   264 		{
       
   265 		Kern::Printf("Trapped exception");
       
   266 		TArmRegSet context1;
       
   267 		TUint32 availmask;
       
   268 		NKern::ThreadGetUserContext(&t.iNThread, &context1, availmask);
       
   269 		XTRAPD(r, XT_DEFAULT, umemput(iExcContextPtr, &context1, sizeof(context1)));
       
   270 
       
   271 		if (r == KErrNone)
       
   272 			{
       
   273 			if (iExcKillThread)
       
   274 				{
       
   275 				// We must preserve PC for software exceptions because execution
       
   276 				// goes back user-side and only then is the thread panicked.
       
   277 				TArmReg r15usr = context1.iR15;
       
   278 				ModifyContext(context1);
       
   279 				context1.iR15 = r15usr;
       
   280 				NKern::ThreadSetUserContext(&t.iNThread, &context1);
       
   281 
       
   282 				TArmRegSet context2;
       
   283 				memclr(&context2, sizeof context2);
       
   284 				NKern::ThreadGetUserContext(&t.iNThread, &context2, availmask);
       
   285 				r = CheckSetContext(context1, context2, availmask);
       
   286 				}
       
   287 			else
       
   288 				{
       
   289 				Kern::ThreadSuspend(t, 1);
       
   290 				handled = ETrue;
       
   291 				}
       
   292 			}
       
   293 		Kern::QueueRequestComplete(iClientThread, aRequestPtr, r);
       
   294 		aStatusPtr = NULL;
       
   295 		}
       
   296 	return handled;
       
   297 	}
       
   298 
       
   299 
       
   300 // called in thread CS
       
   301 void DEventHandler::HandleThreadDeath()
       
   302 	{
       
   303 	DThread& t = Kern::CurrentThread();
       
   304 	if (iDeathStatusPtr && iDeathThreadId == t.iId)
       
   305 		{
       
   306 		Kern::Printf("Trapping thread death: %O", &t);
       
   307 		TArmRegSet context;
       
   308 		TUint32 unused;
       
   309 		NKern::ThreadGetUserContext(&t.iNThread, &context, unused);
       
   310 		XTRAPD(r, XT_DEFAULT, umemput(iDeathContextPtr, &context, sizeof(context)));
       
   311 		Kern::QueueRequestComplete(iClientThread, iClientRequestDeath, r);
       
   312 		iDeathStatusPtr = NULL;
       
   313 		}
       
   314 	}
       
   315 
       
   316 //////////////////////////////////////////////////////////////////////////////
       
   317 
       
   318 class DTestChannel : public DLogicalChannelBase
       
   319 	{
       
   320 public:
       
   321 	virtual ~DTestChannel();
       
   322 protected:
       
   323 	// from DLogicalChannelBase
       
   324 	virtual TInt DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer);
       
   325 	virtual TInt Request(TInt aFunction, TAny* a1, TAny* a2);
       
   326 private:
       
   327 	TInt SetAndGetBackContext(TUint aId, TAny* aContext);
       
   328 	TInt SetAndGetFullContext(TUint aId, TAny* aContext);
       
   329 	void GetContext(TUint aId, TAny* aContext);
       
   330 	void GetKernelContext(TUint aId, TAny* aContext);
       
   331 	void AddUserCallback(TUint aId, TUserCallbackState aCallback);
       
   332 private:
       
   333 	DEventHandler* iHandler;
       
   334 	};
       
   335 
       
   336 
       
   337 // called in thread critical section
       
   338 TInt DTestChannel::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& /*aVer*/)
       
   339 	{
       
   340 	return KErrNone;
       
   341 	}
       
   342 
       
   343 // called in thread critical section
       
   344 DTestChannel::~DTestChannel()
       
   345 	{
       
   346 	if (iHandler)
       
   347 		{
       
   348 		iHandler->Cancel();
       
   349 		iHandler->Close();
       
   350 		}
       
   351 	}
       
   352 
       
   353 TInt DTestChannel::Request(TInt aFunction, TAny* a1, TAny* a2)
       
   354 	{
       
   355 	RContextLdd::TTrapInfo info;
       
   356 	DThread* pT;
       
   357 	TInt r = KErrNone;
       
   358 	switch (aFunction)
       
   359 		{
       
   360 	case RContextLdd::EHook:
       
   361 		NKern::ThreadEnterCS();
       
   362 		iHandler = new DEventHandler;
       
   363 		if (!iHandler)
       
   364 			r = KErrNoMemory;
       
   365 		else
       
   366 			{
       
   367 			r = iHandler->Create(iDevice);
       
   368 			iHandler->iSwExcCounterPtr = (TInt*)a1;
       
   369 			}
       
   370 		NKern::ThreadLeaveCS();
       
   371 		break;
       
   372 	case RContextLdd::EGetLastExc:
       
   373 		r = iHandler->iSwExcLastType;
       
   374 		break;
       
   375 	case RContextLdd::ETrapNextSwExc:
       
   376 	case RContextLdd::ETrapNextHwExc:
       
   377 		umemget(&info, a1, sizeof(info));
       
   378 		if (aFunction == RContextLdd::ETrapNextHwExc)
       
   379 			{
       
   380 			__ASSERT_ALWAYS(iHandler->iSwExcStatusPtr==NULL, Kern::PanicCurrentThread(KClientPanicCat, __LINE__));
       
   381 			iHandler->iHwExcStatusPtr = info.iStatusPtr;
       
   382 			r = iHandler->iClientRequestHwExc->SetStatus(iHandler->iHwExcStatusPtr);
       
   383 			__ASSERT_ALWAYS(r==KErrNone, Kern::PanicCurrentThread(KClientPanicCat, __LINE__));
       
   384 			}
       
   385 		else
       
   386 			{
       
   387 			__ASSERT_ALWAYS(iHandler->iHwExcStatusPtr==NULL, Kern::PanicCurrentThread(KClientPanicCat, __LINE__));
       
   388 			iHandler->iSwExcStatusPtr = info.iStatusPtr;
       
   389 			r = iHandler->iClientRequestSwExc->SetStatus(iHandler->iSwExcStatusPtr);
       
   390 			__ASSERT_ALWAYS(r==KErrNone, Kern::PanicCurrentThread(KClientPanicCat, __LINE__));
       
   391 			}
       
   392 		iHandler->iExcThreadId = info.iThreadId;
       
   393 		iHandler->iExcContextPtr = info.iContextPtr;
       
   394 		iHandler->iExcKillThread = info.iKillThread;
       
   395 		break;
       
   396 	case RContextLdd::ETrapNextDeath:
       
   397 		umemget(&info, a1, sizeof(info));
       
   398 		iHandler->iDeathThreadId = info.iThreadId;
       
   399 		iHandler->iDeathContextPtr = info.iContextPtr;
       
   400 		iHandler->iDeathStatusPtr = info.iStatusPtr;
       
   401 		r = iHandler->iClientRequestDeath->SetStatus(iHandler->iDeathStatusPtr);
       
   402 		__ASSERT_ALWAYS(r==KErrNone, Kern::PanicCurrentThread(KClientPanicCat, __LINE__));
       
   403 		break;
       
   404 	case RContextLdd::EGetContext:
       
   405 		GetContext((TUint)a1, a2);
       
   406 		break;
       
   407 	case RContextLdd::ESetGetContext:
       
   408 		r = SetAndGetBackContext((TUint)a1, a2);
       
   409 		break;
       
   410 	case RContextLdd::ESetGetFullContext:
       
   411 		r = SetAndGetFullContext((TUint)a1, a2);
       
   412 		break;
       
   413 	case RContextLdd::EGetKernelContext:
       
   414 		GetKernelContext((TUint)a1, a2);
       
   415 		break;
       
   416 	case RContextLdd::ESpinInKernel:
       
   417 		r = SpinInKernel((TBool)a1);
       
   418 		break;
       
   419 	case RContextLdd::EAddUserCallback:
       
   420 		AddUserCallback((TUint)a1, (TUserCallbackState)(TUint)a2);
       
   421 		break;
       
   422 	case RContextLdd::EResumeTrappedThread:
       
   423 		pT = ThreadFromId((TUint)a1);
       
   424 		Kern::ThreadResume(*pT);
       
   425 		break;
       
   426 	default:
       
   427 		Kern::PanicCurrentThread(KClientPanicCat, __LINE__);
       
   428 		break;
       
   429 		}
       
   430 	return r;
       
   431 	}
       
   432 
       
   433 
       
   434 TInt DTestChannel::SetAndGetBackContext(TUint aId, TAny* aContext)
       
   435 	{
       
   436 	DThread* pT = ThreadFromId(aId);
       
   437 	__ASSERT_ALWAYS(pT!=NULL, Kern::PanicCurrentThread(KClientPanicCat, __LINE__));
       
   438 
       
   439 	// The following code assumes the inspected thread does not run between the
       
   440 	// set context and get context call.
       
   441 
       
   442 	TArmRegSet context1;
       
   443 	umemget(&context1, aContext, sizeof context1);
       
   444 	NKern::ThreadSetUserContext(&pT->iNThread, &context1);
       
   445 
       
   446 	TArmRegSet context2;
       
   447 	memclr(&context2, sizeof context2);
       
   448 	TUint32 availmask;
       
   449 	NKern::ThreadGetUserContext(&pT->iNThread, &context2, availmask);
       
   450 	umemput(aContext, &context2, sizeof context2);
       
   451 
       
   452 	return CheckSetContext(context1, context2, availmask);
       
   453 	}
       
   454 
       
   455 #ifdef __SMP__
       
   456 class NKTest
       
   457 	{
       
   458 public:
       
   459 	static TBool IsDead(NThreadBase* aT)
       
   460 		{ return aT->iWaitState.ThreadIsDead(); }
       
   461 	};
       
   462 #endif
       
   463 
       
   464 TInt DTestChannel::SetAndGetFullContext(TUint aId, TAny* aContext)
       
   465 	{
       
   466 	DThread* pT = ThreadFromId(aId);
       
   467 	__ASSERT_ALWAYS(pT != NULL, Kern::PanicCurrentThread(KClientPanicCat, __LINE__));
       
   468 	TBool dead;
       
   469 #ifdef __SMP__
       
   470 	dead = NKTest::IsDead(&pT->iNThread);
       
   471 #else
       
   472 	dead = pT->iNThread.iSpare1 == NThreadBase::EDead;
       
   473 #endif
       
   474 	__ASSERT_ALWAYS(dead, Kern::PanicCurrentThread(KClientPanicCat, __LINE__));
       
   475 
       
   476 	TArmFullContext contextData;
       
   477 	umemget(&contextData, aContext, sizeof contextData);
       
   478 	NKern::ThreadSetUserContext(&pT->iNThread, &contextData.iUserContext);
       
   479 
       
   480 	NKern::ThreadGetUserContext(&pT->iNThread, &contextData.iUserContext, contextData.iUserAvail);
       
   481 	NKern::ThreadGetSystemContext(&pT->iNThread, &contextData.iSystemContext, contextData.iSystemAvail);
       
   482 
       
   483 	umemput(aContext, &contextData, sizeof contextData);
       
   484 
       
   485 	return KErrNone;
       
   486 	}
       
   487 
       
   488 void DTestChannel::GetContext(TUint aId, TAny* aContext)
       
   489 	{
       
   490 	DThread* pT = ThreadFromId(aId);
       
   491 	__ASSERT_ALWAYS(pT!=NULL, Kern::PanicCurrentThread(KClientPanicCat, __LINE__));
       
   492 
       
   493 	TArmRegSet context;
       
   494 	memclr(&context, sizeof context);
       
   495 	TUint32 unused;
       
   496 	NKern::ThreadGetUserContext(&pT->iNThread, &context, unused);
       
   497 	umemput(aContext, &context, sizeof context);
       
   498 	}
       
   499 
       
   500 void DTestChannel::GetKernelContext(TUint aId, TAny* aContext)
       
   501 	{
       
   502 	DThread* pT = ThreadFromId(aId);
       
   503 	__ASSERT_ALWAYS(pT!=NULL, Kern::PanicCurrentThread(KClientPanicCat, __LINE__));
       
   504 
       
   505 	TArmRegSet context;
       
   506 	memclr(&context, sizeof context);
       
   507 	TUint32 unused;
       
   508 	NKern::ThreadGetSystemContext(&pT->iNThread, &context, unused);
       
   509 	umemput(aContext, &context, sizeof context);
       
   510 	}
       
   511 
       
   512 void DTestChannel::AddUserCallback(TUint aId, TUserCallbackState aCallback)
       
   513 	{
       
   514 	DThread* pT = ThreadFromId(aId);
       
   515 	__ASSERT_ALWAYS(pT!=NULL, Kern::PanicCurrentThread(KClientPanicCat, __LINE__));
       
   516 
       
   517 	switch (aCallback)
       
   518 		{
       
   519 	case ESpinningCallback:
       
   520 		KernTest::Test(KernTest::EUserModeCallbackSpin, pT);
       
   521 		break;
       
   522 	case ESleepingCallback:
       
   523 		KernTest::Test(KernTest::EUserModeCallbackSleep, pT);
       
   524 		break;
       
   525 	default:
       
   526 		Kern::PanicCurrentThread(KClientPanicCat, __LINE__);
       
   527 		}
       
   528 	}
       
   529 
       
   530 //////////////////////////////////////////////////////////////////////////////
       
   531 
       
   532 class DTestFactory : public DLogicalDevice
       
   533 	{
       
   534 public:
       
   535 	DTestFactory();
       
   536 	// from DLogicalDevice
       
   537 	virtual TInt Install();
       
   538 	virtual void GetCaps(TDes8& aDes) const;
       
   539 	virtual TInt Create(DLogicalChannelBase*& aChannel);
       
   540 	};
       
   541 
       
   542 DTestFactory::DTestFactory()
       
   543     {
       
   544     iVersion = RContextLdd::Version();
       
   545     // iParseMask = 0; // no unit, no info, no PDD
       
   546     // iUnitsMask = 0; // only one thing
       
   547     }
       
   548 
       
   549 TInt DTestFactory::Create(DLogicalChannelBase*& aChannel)
       
   550     {
       
   551 	aChannel=new DTestChannel;
       
   552 	return aChannel ? KErrNone : KErrNoMemory;
       
   553     }
       
   554 
       
   555 TInt DTestFactory::Install()
       
   556     {
       
   557     return SetName(&KTestLddName);
       
   558     }
       
   559 
       
   560 void DTestFactory::GetCaps(TDes8& /*aDes*/) const
       
   561     {
       
   562     }
       
   563 
       
   564 //////////////////////////////////////////////////////////////////////////////
       
   565 
       
   566 DECLARE_STANDARD_LDD()
       
   567 	{
       
   568     return new DTestFactory;
       
   569 	}