os/kernelhwsrv/kerneltest/e32test/debug/t_context.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
sl@0
     1
// Copyright (c) 2003-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\debug\t_context.cpp
sl@0
    15
// Overview:
sl@0
    16
// Exercise kernel-side functions to get, set user-side context and 
sl@0
    17
// kernel-side exception handlers.
sl@0
    18
// API Information:
sl@0
    19
// RBusLogicalChannel, DLogicalChannel.
sl@0
    20
// Details:
sl@0
    21
// - Load the context logical device driver, open user side handle to 
sl@0
    22
// a LDD channel and check software exception scheme when handle is 
sl@0
    23
// not created.
sl@0
    24
// - Check user-side handler called when kernel-side handler is not
sl@0
    25
// created and exception is handled as expected.
sl@0
    26
// - Make a synchronous Kernel Executive type request to logical channel
sl@0
    27
// for a specific functionality and check that it is as expected.
sl@0
    28
// - Check that kernel-side handler is not triggered by IsExceptionHandler 
sl@0
    29
// method.
sl@0
    30
// - Test user-side, kernel-side handlers are as expected.
sl@0
    31
// - In the context of thread taking hardware exception with synchronous
sl@0
    32
// and asynchronous killing:
sl@0
    33
// - check context captured in hardware exception hook and
sl@0
    34
// context captured in RemoveThread hook are as expected.
sl@0
    35
// - In the context of thread taking software exception with synchronous 
sl@0
    36
// and asynchronous killing:
sl@0
    37
// - check context captured in software exception hook and
sl@0
    38
// context captured in RemoveThread hook are as expected.
sl@0
    39
// - In the context of thread blocked on WFAR:
sl@0
    40
// - check context captured while thread is blocked, 
sl@0
    41
// context can be modified while thread is blocked, 
sl@0
    42
// context captured in RemoveThread hook are as expected.
sl@0
    43
// - In the context of thread killed after being pre-empted by interrupt 
sl@0
    44
// while in user mode:
sl@0
    45
// - check context captured while thread is spinning, context can be 
sl@0
    46
// modified while thread is blocked, context captured in RemoveThread 
sl@0
    47
// hook are as expected.
sl@0
    48
// - Check whether heap has been corrupted by all the tests.
sl@0
    49
// - Check that the system doesn't crash when the context of a dead thread is
sl@0
    50
// set or retrieved.
sl@0
    51
// Platforms/Drives/Compatibility:
sl@0
    52
// Hardware (Automatic). 
sl@0
    53
// Assumptions/Requirement/Pre-requisites:
sl@0
    54
// Failures and causes:
sl@0
    55
// Base Port information:
sl@0
    56
// 
sl@0
    57
//
sl@0
    58
sl@0
    59
#define __E32TEST_EXTENSION__
sl@0
    60
#include <e32test.h>
sl@0
    61
#include <e32svr.h>
sl@0
    62
#include <e32def.h>
sl@0
    63
#include <e32def_private.h>
sl@0
    64
#include <u32hal.h>
sl@0
    65
#include "d_context.h"
sl@0
    66
#include "context.h"
sl@0
    67
sl@0
    68
enum TKillMode 
sl@0
    69
	{ 
sl@0
    70
	ESynchronousKill, // thread kills itself in exception handler
sl@0
    71
	EAsynchronousKill // thread suspends itself in exception handler and is killed by main thread
sl@0
    72
	};
sl@0
    73
sl@0
    74
_LIT(KUserExecPanic, "USER-EXEC");
sl@0
    75
sl@0
    76
RTest test(_L("T_CONTEXT"));
sl@0
    77
sl@0
    78
TInt KernelExcCount; // incremented when user-side exception handler called
sl@0
    79
TInt UserExcCount;   // incremented when kernel-side exception handler called
sl@0
    80
TExcType LastUserExcType; // set by user-side exception handler when called
sl@0
    81
sl@0
    82
RContextLdd Channel;
sl@0
    83
sl@0
    84
sl@0
    85
TInt CallDeviceDriverAndSpin(TAny* aExpected)
sl@0
    86
	{
sl@0
    87
	TArmRegSet* expectedContext = (TArmRegSet*)aExpected;
sl@0
    88
	expectedContext->iR13 = Channel.SpinInKernel(EFalse);
sl@0
    89
	Channel.SpinInKernel(ETrue);
sl@0
    90
	return 0;
sl@0
    91
	}
sl@0
    92
sl@0
    93
TInt UserRaiseExceptionThread(TAny* aExcType)
sl@0
    94
	{
sl@0
    95
	TExcType e = static_cast<TExcType>(reinterpret_cast<TInt>(aExcType));
sl@0
    96
	User::RaiseException(e);
sl@0
    97
	return 0;
sl@0
    98
	}
sl@0
    99
sl@0
   100
TInt RThreadRaiseExceptionThread(TAny* aExcType)
sl@0
   101
	{
sl@0
   102
	TExcType e = static_cast<TExcType>(reinterpret_cast<TInt>(aExcType));
sl@0
   103
	User::RaiseException(e);
sl@0
   104
	return 0;
sl@0
   105
	}
sl@0
   106
sl@0
   107
void UserExceptionHandler(TExcType aType)
sl@0
   108
	{
sl@0
   109
	// Check kernel-side handler was called before user-side one
sl@0
   110
	if (Channel.IsHooked() && KernelExcCount != 1)
sl@0
   111
		User::Invariant(); // force failure in RaiseExceptionHarness()
sl@0
   112
sl@0
   113
	LastUserExcType = aType;
sl@0
   114
	UserExcCount++;
sl@0
   115
	User::Panic(KUserExecPanic, ECausedException);
sl@0
   116
	}
sl@0
   117
sl@0
   118
TInt UserTrapExceptionThread(TAny* aExcType)
sl@0
   119
	{
sl@0
   120
	TInt r = User::SetExceptionHandler(UserExceptionHandler, 0xFFFFFFFF);
sl@0
   121
	if (r != KErrNone)
sl@0
   122
		return 0; // force failure in RaiseExceptionHarness()
sl@0
   123
	TExcType e = static_cast<TExcType>(reinterpret_cast<TInt>(aExcType));
sl@0
   124
	User::RaiseException(e);
sl@0
   125
	return 0;
sl@0
   126
	}
sl@0
   127
	
sl@0
   128
TInt NaturalDeathFunc(TAny*)
sl@0
   129
	{// Don't do too much but be sure to complete.
sl@0
   130
	return KErrNone;
sl@0
   131
	}
sl@0
   132
sl@0
   133
sl@0
   134
void RaiseExceptionHarness(TThreadFunction aFn, TExcType aType)
sl@0
   135
	{
sl@0
   136
	RThread t;
sl@0
   137
	TInt r = t.Create(_L("RaiseException"), aFn, KDefaultStackSize, NULL, 
sl@0
   138
						reinterpret_cast<TAny*>(aType));
sl@0
   139
	test(r == KErrNone);
sl@0
   140
sl@0
   141
	TRequestStatus s;
sl@0
   142
	t.Logon(s);
sl@0
   143
	TBool oldJitSetting = User::JustInTime();
sl@0
   144
	User::SetJustInTime(EFalse);
sl@0
   145
	t.Resume();
sl@0
   146
	User::WaitForRequest(s);
sl@0
   147
	User::SetJustInTime(oldJitSetting);
sl@0
   148
sl@0
   149
	test(t.ExitType() == EExitPanic);
sl@0
   150
	test(t.ExitCategory() == KUserExecPanic);
sl@0
   151
	test(t.ExitReason() == ECausedException);
sl@0
   152
	CLOSE_AND_WAIT(t);
sl@0
   153
	}
sl@0
   154
sl@0
   155
sl@0
   156
void TestSwExcNoHandlers()
sl@0
   157
	{
sl@0
   158
	test.Next(_L("Check software exception scheme when no handler"));
sl@0
   159
sl@0
   160
	RaiseExceptionHarness(UserRaiseExceptionThread, EExcGeneral);
sl@0
   161
	RaiseExceptionHarness(RThreadRaiseExceptionThread, EExcGeneral);
sl@0
   162
	}
sl@0
   163
sl@0
   164
void TestUserSwExcHandlerAlone()
sl@0
   165
	{
sl@0
   166
	test.Next(_L("Check user-side handler called when no kernel-side handler"));
sl@0
   167
sl@0
   168
	UserExcCount = 0;
sl@0
   169
	RaiseExceptionHarness(UserTrapExceptionThread, EExcIntegerDivideByZero);
sl@0
   170
	test(LastUserExcType == EExcIntegerDivideByZero);
sl@0
   171
	test(UserExcCount == 1);
sl@0
   172
	}
sl@0
   173
sl@0
   174
void TestUserAndKernelSwExcHandlers()
sl@0
   175
	{
sl@0
   176
	test.Next(_L("Check kernel-side exception handler"));
sl@0
   177
	test.Start(_L("Check kernel-side handler called"));
sl@0
   178
sl@0
   179
	KernelExcCount = 0;
sl@0
   180
	RaiseExceptionHarness(UserRaiseExceptionThread, EExcUserInterrupt);
sl@0
   181
	test(KernelExcCount == 1);
sl@0
   182
	test(Channel.LastException() == EExcUserInterrupt);
sl@0
   183
sl@0
   184
	KernelExcCount = 0;
sl@0
   185
	RaiseExceptionHarness(RThreadRaiseExceptionThread, EExcIntegerDivideByZero);
sl@0
   186
	test(KernelExcCount == 1);
sl@0
   187
	test(Channel.LastException() == EExcIntegerDivideByZero);
sl@0
   188
sl@0
   189
	test.Next(_L("Check kernel-side handler not triggered by IsExceptionHandler()"));
sl@0
   190
	
sl@0
   191
	KernelExcCount = 0;
sl@0
   192
	(void) User::IsExceptionHandled(EExcUserInterrupt);
sl@0
   193
	test(KernelExcCount == 0);
sl@0
   194
sl@0
   195
	test.Next(_L("Check user-side + kernel-side handler"));
sl@0
   196
sl@0
   197
	UserExcCount = 0;
sl@0
   198
	KernelExcCount = 0;
sl@0
   199
	RaiseExceptionHarness(UserTrapExceptionThread, EExcIntegerDivideByZero);
sl@0
   200
	test(LastUserExcType == EExcIntegerDivideByZero);
sl@0
   201
	test(UserExcCount == 1);
sl@0
   202
	test(KernelExcCount == 1);
sl@0
   203
	test(Channel.LastException() == EExcIntegerDivideByZero);
sl@0
   204
sl@0
   205
	test.End();
sl@0
   206
	}
sl@0
   207
sl@0
   208
sl@0
   209
//////////////////////////////////////////////////////////////////////////////
sl@0
   210
sl@0
   211
void DumpContext(const TDesC& aTitle, TArmRegSet& aContext)
sl@0
   212
	{
sl@0
   213
	test.Printf(_L("%S\n"), &aTitle);
sl@0
   214
	test.Printf(_L("  r0 =%08x r1 =%08x r2 =%08x r3 =%08x\n"),aContext.iR0,aContext.iR1,aContext.iR2,aContext.iR3);
sl@0
   215
	test.Printf(_L("  r4 =%08x r5 =%08x r6 =%08x r7 =%08x\n"),aContext.iR4,aContext.iR5,aContext.iR6,aContext.iR7);
sl@0
   216
	test.Printf(_L("  r8 =%08x r9 =%08x r10=%08x r11=%08x\n"),aContext.iR8,aContext.iR9,aContext.iR10,aContext.iR11);
sl@0
   217
	test.Printf(_L("  r12=%08x r13=%08x r14=%08x r15=%08x\n"),aContext.iR12,aContext.iR13,aContext.iR14,aContext.iR15);
sl@0
   218
	test.Printf(_L("  cpsr=%08x dacr=%08x\n"),aContext.iFlags, aContext.iDacr);
sl@0
   219
	}
sl@0
   220
sl@0
   221
void ModifyContext(TArmRegSet& aContext)
sl@0
   222
	{
sl@0
   223
	TArmReg* end = (TArmReg*)(&aContext+1);
sl@0
   224
	for (TArmReg* p = (TArmReg*)&aContext; p<end; ++p)
sl@0
   225
		*p = ~*p;
sl@0
   226
	}
sl@0
   227
sl@0
   228
sl@0
   229
void TestHwExcContext(TKillMode aKillMode, TUserCallbackState aCallback)
sl@0
   230
	{
sl@0
   231
	test.Next(_L("Check context of thread taking hardware exception"));
sl@0
   232
	if (aKillMode == EAsynchronousKill)
sl@0
   233
		test.Printf(_L("Thread will be asynchronously killed\n"));
sl@0
   234
	else
sl@0
   235
		test.Printf(_L("Thread will kill itself\n"));
sl@0
   236
sl@0
   237
	TArmRegSet expectedContext;
sl@0
   238
	RThread t;
sl@0
   239
	TInt r = t.Create(_L("ContextHwExc"), ThreadContextHwExc, KDefaultStackSize, NULL, &expectedContext);
sl@0
   240
	test(r == KErrNone);
sl@0
   241
sl@0
   242
	TArmRegSet exceptionContext;
sl@0
   243
	TRequestStatus exceptionStatus;
sl@0
   244
	Channel.TrapNextHwExc(t.Id(), &exceptionContext, exceptionStatus, aKillMode==ESynchronousKill);
sl@0
   245
sl@0
   246
	TRequestStatus deathStatus;
sl@0
   247
	TArmRegSet deathContext;
sl@0
   248
	Channel.TrapNextDeath(t.Id(), &deathContext, deathStatus);
sl@0
   249
sl@0
   250
	TBool oldJitSetting = User::JustInTime();
sl@0
   251
	User::SetJustInTime(EFalse);
sl@0
   252
	t.Resume();
sl@0
   253
	User::WaitForRequest(exceptionStatus);
sl@0
   254
	User::SetJustInTime(oldJitSetting);
sl@0
   255
	test(exceptionStatus == KErrNone); // See CheckSetContext() in LDD
sl@0
   256
sl@0
   257
	test.Start(_L("Check context captured in hardware exception hook"));
sl@0
   258
	exceptionContext.iR15 += 4; // See CheckContextHwExc()
sl@0
   259
	DumpContext(_L("Expected context:"), expectedContext);
sl@0
   260
	DumpContext(_L("Context in hw exception hook:"), exceptionContext);
sl@0
   261
	test(CheckContextHwExc(&exceptionContext, &expectedContext));
sl@0
   262
sl@0
   263
	if (aCallback != ENoCallback)
sl@0
   264
		{
sl@0
   265
		test.Printf(_L("Adding user callback type %d\n"), aCallback);
sl@0
   266
		Channel.AddUserCallback(t.Id(), aCallback);
sl@0
   267
		Channel.ResumeTrappedThread(t.Id());
sl@0
   268
		User::After(500000);
sl@0
   269
sl@0
   270
		test.Next(_L("Check context captured while thread is in callback"));
sl@0
   271
		TArmRegSet callbackContext;
sl@0
   272
		Channel.GetContext(t.Id(), &callbackContext);
sl@0
   273
		callbackContext.iR15 += 4; // See CheckContextHwExc()
sl@0
   274
		DumpContext(_L("Expected context:"), expectedContext);
sl@0
   275
		DumpContext(_L("Actual context:"), callbackContext);
sl@0
   276
		test(CheckContextHwExc(&callbackContext, &expectedContext));
sl@0
   277
		}
sl@0
   278
sl@0
   279
	ModifyContext(expectedContext);
sl@0
   280
	DumpContext(_L("Expected context after modification:"), expectedContext);
sl@0
   281
sl@0
   282
	if (aKillMode == EAsynchronousKill)
sl@0
   283
		{
sl@0
   284
		test.Next(_L("Check context can be modified by another thread"));
sl@0
   285
		TArmRegSet modifiedContext = expectedContext;
sl@0
   286
		test(Channel.SetAndGetBackContext(t.Id(), &modifiedContext) == KErrNone);
sl@0
   287
		modifiedContext.iR15 = exceptionContext.iR15; // See CheckContextHwExc()
sl@0
   288
		DumpContext(_L("Actual context after modification:"), modifiedContext);
sl@0
   289
		test(CheckContextHwExc(&modifiedContext, &expectedContext));
sl@0
   290
sl@0
   291
		User::SetJustInTime(EFalse);
sl@0
   292
		t.Panic(_L("TEST"), 42);
sl@0
   293
		}
sl@0
   294
	else
sl@0
   295
		{
sl@0
   296
		// The thread has modified its own user context in the exception hook.
sl@0
   297
		User::SetJustInTime(EFalse);
sl@0
   298
		}
sl@0
   299
sl@0
   300
	User::WaitForRequest(deathStatus);
sl@0
   301
	User::SetJustInTime(oldJitSetting);
sl@0
   302
	CLOSE_AND_WAIT(t);
sl@0
   303
sl@0
   304
	test.Next(_L("Check context captured in RemoveThread hook"));
sl@0
   305
	deathContext.iR15 = exceptionContext.iR15; // See CheckContextHwExc()
sl@0
   306
	DumpContext(_L("context in RemoveThread hook:"), deathContext);
sl@0
   307
	test(CheckContextHwExc(&deathContext, &expectedContext));
sl@0
   308
	test.End();
sl@0
   309
	}
sl@0
   310
sl@0
   311
sl@0
   312
void TestSwExcContext(TKillMode aKillMode, TUserCallbackState aCallback)
sl@0
   313
	{
sl@0
   314
	test.Next(_L("Check context of thread taking software exception (slow executive call)"));
sl@0
   315
	if (aKillMode == EAsynchronousKill)
sl@0
   316
		test.Printf(_L("Thread will be asynchronously killed\n"));
sl@0
   317
	else
sl@0
   318
		test.Printf(_L("Thread will kill itself\n"));
sl@0
   319
sl@0
   320
	TArmRegSet expectedContext;
sl@0
   321
	RThread t;
sl@0
   322
	TInt r = t.Create(_L("ContextSwExc"), ThreadContextSwExc, KDefaultStackSize, NULL, &expectedContext);
sl@0
   323
	test(r == KErrNone);
sl@0
   324
sl@0
   325
	TArmRegSet exceptionContext;
sl@0
   326
	TRequestStatus exceptionStatus;
sl@0
   327
	Channel.TrapNextSwExc(t.Id(), &exceptionContext, exceptionStatus, aKillMode == ESynchronousKill);
sl@0
   328
sl@0
   329
	TRequestStatus deathStatus;
sl@0
   330
	TArmRegSet deathContext;
sl@0
   331
	Channel.TrapNextDeath(t.Id(), &deathContext, deathStatus);
sl@0
   332
sl@0
   333
	TBool oldJitSetting = User::JustInTime();
sl@0
   334
	User::SetJustInTime(EFalse);
sl@0
   335
	t.Resume();
sl@0
   336
	User::WaitForRequest(exceptionStatus);
sl@0
   337
	User::SetJustInTime(oldJitSetting);
sl@0
   338
	test(exceptionStatus == KErrNone); // See CheckSetContext() in LDD
sl@0
   339
sl@0
   340
	test.Start(_L("Check context captured in software exception hook"));
sl@0
   341
	DumpContext(_L("Expected context:"), expectedContext);
sl@0
   342
	DumpContext(_L("Context in sw exception hook:"), exceptionContext);
sl@0
   343
	test(CheckContextSwExc(&exceptionContext, &expectedContext));
sl@0
   344
sl@0
   345
	if (aCallback != ENoCallback)
sl@0
   346
		{
sl@0
   347
		test.Printf(_L("Adding user callback type %d\n"), aCallback);
sl@0
   348
		Channel.AddUserCallback(t.Id(), aCallback);
sl@0
   349
		Channel.ResumeTrappedThread(t.Id());
sl@0
   350
		User::After(500000);
sl@0
   351
sl@0
   352
		test.Next(_L("Check context captured while thread is in callback"));
sl@0
   353
		TArmRegSet callbackContext;
sl@0
   354
		Channel.GetContext(t.Id(), &callbackContext);
sl@0
   355
		DumpContext(_L("Expected context:"), expectedContext);
sl@0
   356
		DumpContext(_L("Actual context:"), callbackContext);
sl@0
   357
		test(CheckContextSwExc(&callbackContext, &expectedContext));
sl@0
   358
		}
sl@0
   359
sl@0
   360
	ModifyContext(expectedContext);
sl@0
   361
	DumpContext(_L("Expected context after modification:"), expectedContext);
sl@0
   362
sl@0
   363
	if (aKillMode == EAsynchronousKill)
sl@0
   364
		{
sl@0
   365
		test.Next(_L("Check context can be modified by another thread"));
sl@0
   366
		TArmRegSet modifiedContext = expectedContext;
sl@0
   367
		test(Channel.SetAndGetBackContext(t.Id(), &modifiedContext) == KErrNone);
sl@0
   368
		modifiedContext.iR14 = exceptionContext.iR14; // See CheckContextSwExc()
sl@0
   369
		modifiedContext.iR15 = exceptionContext.iR15; // See CheckContextSwExc()
sl@0
   370
		DumpContext(_L("Actual context after modification:"), modifiedContext);
sl@0
   371
		test(CheckContextSwExc(&modifiedContext, &expectedContext));
sl@0
   372
sl@0
   373
		User::SetJustInTime(EFalse);
sl@0
   374
		t.Panic(_L("TEST"), 24);
sl@0
   375
		}
sl@0
   376
	else
sl@0
   377
		{
sl@0
   378
		// The thread has modified its own user context in the exception hook.
sl@0
   379
		User::SetJustInTime(EFalse);
sl@0
   380
		}
sl@0
   381
sl@0
   382
	User::WaitForRequest(deathStatus);
sl@0
   383
	User::SetJustInTime(oldJitSetting);
sl@0
   384
	CLOSE_AND_WAIT(t);
sl@0
   385
sl@0
   386
	test.Next(_L("Check context captured in RemoveThread hook"));
sl@0
   387
	deathContext.iR14 = exceptionContext.iR14; // See CheckContextSwExc()
sl@0
   388
	deathContext.iR15 = exceptionContext.iR15; // See CheckContextSwExc()
sl@0
   389
	DumpContext(_L("context in RemoveThread hook:"), deathContext);
sl@0
   390
	test(CheckContextSwExc(&deathContext, &expectedContext));
sl@0
   391
	test.End();
sl@0
   392
	}
sl@0
   393
sl@0
   394
void TestKillWFAR(TUserCallbackState aCallback)
sl@0
   395
	{
sl@0
   396
	test.Next(_L("Check context of thread blocked on WFAR"));
sl@0
   397
sl@0
   398
	TArmRegSet expectedContext;
sl@0
   399
	RThread t;
sl@0
   400
	TInt r = t.Create(_L("ContextWFAR"), ThreadContextWFAR, KDefaultStackSize, NULL, &expectedContext);
sl@0
   401
	test(r == KErrNone);
sl@0
   402
sl@0
   403
	TRequestStatus deathStatus;
sl@0
   404
	TArmRegSet deathContext;
sl@0
   405
	Channel.TrapNextDeath(t.Id(), &deathContext, deathStatus);
sl@0
   406
sl@0
   407
	// Boost thread's priority and kick it off.  This ensures we'll 
sl@0
   408
	// run again only after it is blocked on its request semaphore.
sl@0
   409
	t.SetPriority(EPriorityMore);
sl@0
   410
	t.Resume();
sl@0
   411
sl@0
   412
	if (aCallback != ENoCallback)
sl@0
   413
		{
sl@0
   414
		test.Printf(_L("Adding user callback type %d\n"), aCallback);
sl@0
   415
		Channel.AddUserCallback(t.Id(), aCallback);
sl@0
   416
		t.SetPriority(EPriorityNormal);
sl@0
   417
		t.RequestSignal();
sl@0
   418
		User::After(500000);
sl@0
   419
		}
sl@0
   420
sl@0
   421
	test.Start(_L("Check context captured while thread is blocked"));
sl@0
   422
	TArmRegSet blockedContext;
sl@0
   423
	Channel.GetContext(t.Id(), &blockedContext);
sl@0
   424
	DumpContext(_L("Expected context:"), expectedContext);
sl@0
   425
	DumpContext(_L("Actual context:"), blockedContext);
sl@0
   426
	test(CheckContextWFAR(&blockedContext, &expectedContext));
sl@0
   427
sl@0
   428
	test.Next(_L("Check context can be modified while thread is blocked"));
sl@0
   429
	ModifyContext(expectedContext);
sl@0
   430
	expectedContext.iR14 = blockedContext.iR14; // See CheckContextWFAR()
sl@0
   431
	expectedContext.iR15 = blockedContext.iR15; // See CheckContextWFAR()
sl@0
   432
	TArmRegSet modifiedContext = expectedContext;
sl@0
   433
	test(Channel.SetAndGetBackContext(t.Id(), &modifiedContext) == KErrNone);
sl@0
   434
	DumpContext(_L("Expected context after modification:"), expectedContext);
sl@0
   435
	DumpContext(_L("Actual context after modification:"), modifiedContext);
sl@0
   436
	test(CheckContextWFAR(&modifiedContext, &expectedContext));
sl@0
   437
	
sl@0
   438
	TBool oldJitSetting = User::JustInTime();
sl@0
   439
	User::SetJustInTime(EFalse);
sl@0
   440
	t.Panic(_L("TEST"), 999);
sl@0
   441
	User::WaitForRequest(deathStatus);
sl@0
   442
	User::SetJustInTime(oldJitSetting);
sl@0
   443
	CLOSE_AND_WAIT(t);
sl@0
   444
sl@0
   445
	test.Next(_L("Check context captured in RemoveThread hook"));
sl@0
   446
	DumpContext(_L("Expected context:"), expectedContext);
sl@0
   447
	DumpContext(_L("context in RemoveThread hook:\n"), deathContext);
sl@0
   448
	test(CheckContextWFARDied(&deathContext, &expectedContext));
sl@0
   449
	test.End();
sl@0
   450
	}
sl@0
   451
sl@0
   452
void TestKillInterrupt(TUserCallbackState aCallback)
sl@0
   453
	{
sl@0
   454
	test.Next(_L("Check context of thread killed after being preempted by interrupt while in user mode"));
sl@0
   455
sl@0
   456
	TArmRegSet expectedContext;
sl@0
   457
	RThread t;
sl@0
   458
	TInt r = t.Create(_L("ContextKillInterrupt"), ThreadContextUserInt, KDefaultStackSize, NULL, &expectedContext);
sl@0
   459
	test(r == KErrNone);
sl@0
   460
sl@0
   461
	TArmRegSet trappedContext;
sl@0
   462
	TRequestStatus trapStatus;
sl@0
   463
	Channel.TrapNextDeath(t.Id(), &trappedContext, trapStatus);
sl@0
   464
	
sl@0
   465
	t.Resume();
sl@0
   466
	User::After(500000);
sl@0
   467
sl@0
   468
	if (aCallback != ENoCallback)
sl@0
   469
		{
sl@0
   470
		test.Printf(_L("Adding user callback type %d\n"), aCallback);
sl@0
   471
		Channel.AddUserCallback(t.Id(), aCallback);
sl@0
   472
		User::After(500000);
sl@0
   473
		}
sl@0
   474
sl@0
   475
	test.Start(_L("Check context captured while thread is spinning"));
sl@0
   476
	TArmRegSet spinContext;
sl@0
   477
	Channel.GetContext(t.Id(), &spinContext);
sl@0
   478
	DumpContext(_L("Expected context:"), expectedContext);
sl@0
   479
	DumpContext(_L("Actual context:"), spinContext);
sl@0
   480
	test(CheckContextUserInt(&spinContext, &expectedContext));
sl@0
   481
sl@0
   482
	test.Next(_L("Check context can be modified while thread is spinning"));
sl@0
   483
	ModifyContext(expectedContext);
sl@0
   484
	expectedContext.iR15 = spinContext.iR15; // see CheckContextUserInt()
sl@0
   485
	expectedContext.iFlags = spinContext.iFlags; // must be left unmodified
sl@0
   486
	expectedContext.iDacr = spinContext.iDacr; // must be left unmodified
sl@0
   487
	DumpContext(_L("Expected context after modification:"), expectedContext);
sl@0
   488
	TArmRegSet modifiedContext = expectedContext;
sl@0
   489
	test(Channel.SetAndGetBackContext(t.Id(), &modifiedContext) == KErrNone);
sl@0
   490
	DumpContext(_L("Actual context after modification:"), modifiedContext);
sl@0
   491
	test(CheckContextUserInt(&modifiedContext, &expectedContext));
sl@0
   492
	
sl@0
   493
	TBool oldJitSetting = User::JustInTime();
sl@0
   494
	User::SetJustInTime(EFalse);
sl@0
   495
	t.Kill(-1);
sl@0
   496
	User::WaitForRequest(trapStatus);
sl@0
   497
	User::SetJustInTime(oldJitSetting);
sl@0
   498
	CLOSE_AND_WAIT(t);
sl@0
   499
sl@0
   500
	test.Next(_L("Check context captured in RemoveThread hook"));
sl@0
   501
	DumpContext(_L("Expected context:"), expectedContext);
sl@0
   502
	DumpContext(_L("Trapped context:"), trappedContext);
sl@0
   503
	test(CheckContextUserIntDied(&trappedContext, &expectedContext));
sl@0
   504
	test.End();
sl@0
   505
	}
sl@0
   506
sl@0
   507
void TestKernelContext()
sl@0
   508
	{
sl@0
   509
	test.Start(_L("Test kernel context function"));
sl@0
   510
	
sl@0
   511
	TArmRegSet kernelContext, expectedContext;
sl@0
   512
	for (TInt i=0; i<15; ++i)
sl@0
   513
		*(((TUint32*)&expectedContext)+i) = 0xa0000000 + i;
sl@0
   514
	
sl@0
   515
	RThread t;
sl@0
   516
	TInt r = t.Create(_L("SpinInKernel"), CallDeviceDriverAndSpin, KDefaultStackSize, NULL, &expectedContext);
sl@0
   517
	test(r == KErrNone);
sl@0
   518
	t.Resume();
sl@0
   519
	
sl@0
   520
	User::After(500000);
sl@0
   521
	Channel.GetKernelContext(t.Id(), &kernelContext);
sl@0
   522
	
sl@0
   523
	TBool oldJitSetting = User::JustInTime();
sl@0
   524
	User::SetJustInTime(EFalse);
sl@0
   525
	t.Kill(-1);
sl@0
   526
	User::SetJustInTime(oldJitSetting);
sl@0
   527
	CLOSE_AND_WAIT(t);
sl@0
   528
sl@0
   529
	test.Next(_L("Check kernel context is as expected"));
sl@0
   530
	DumpContext(_L("Expected context:"), expectedContext);
sl@0
   531
	DumpContext(_L("Actual context:"), kernelContext);
sl@0
   532
	test(CheckContextKernel(&kernelContext, &expectedContext));
sl@0
   533
sl@0
   534
	test.End();
sl@0
   535
	}
sl@0
   536
sl@0
   537
void TestNaturalDeathContext()
sl@0
   538
	{
sl@0
   539
	test.Start(_L("Test setting and retrieving the context of a dead thread"));
sl@0
   540
	TArmFullContext context;
sl@0
   541
	memclr(&context, sizeof context);
sl@0
   542
sl@0
   543
	RThread t;
sl@0
   544
	TInt r = t.Create(_L("NaturalDeath"), NaturalDeathFunc, KDefaultStackSize, NULL, NULL);
sl@0
   545
	test_KErrNone(r);
sl@0
   546
	t.Resume();
sl@0
   547
	
sl@0
   548
	User::After(500000);
sl@0
   549
	Channel.SetAndGetFullContext(t.Id(), &context);
sl@0
   550
sl@0
   551
	// Verify that no registers should be available for this dead thread.
sl@0
   552
	test_Equal(0, context.iUserAvail);
sl@0
   553
	test_Equal(0, context.iSystemAvail);
sl@0
   554
sl@0
   555
	t.Close();
sl@0
   556
	test.End();
sl@0
   557
	}
sl@0
   558
sl@0
   559
TInt E32Main()
sl@0
   560
	{
sl@0
   561
	test.Title();
sl@0
   562
	
sl@0
   563
	test.Start(_L("Loading LDD"));
sl@0
   564
	TInt r = User::LoadLogicalDevice(_L("D_CONTEXT"));
sl@0
   565
	test(r == KErrNone || r == KErrAlreadyExists);
sl@0
   566
	
sl@0
   567
	// Must be after LDD loading because User::FreeLogicalDevice() does not
sl@0
   568
	// free anything currently.
sl@0
   569
	__KHEAP_MARK; 
sl@0
   570
sl@0
   571
	test.Next(_L("Opening LDD channel"));
sl@0
   572
	r = Channel.Open();
sl@0
   573
	test(r == KErrNone);
sl@0
   574
sl@0
   575
	TestSwExcNoHandlers();
sl@0
   576
	TestUserSwExcHandlerAlone();
sl@0
   577
sl@0
   578
	test.Next(_L("Enable event hook"));
sl@0
   579
	r = Channel.Hook(&KernelExcCount);
sl@0
   580
	test(r == KErrNone);
sl@0
   581
sl@0
   582
	TestUserAndKernelSwExcHandlers();
sl@0
   583
	TestHwExcContext(ESynchronousKill, ENoCallback);
sl@0
   584
	TestHwExcContext(EAsynchronousKill, ENoCallback);
sl@0
   585
	TestSwExcContext(ESynchronousKill, ENoCallback);
sl@0
   586
	TestSwExcContext(EAsynchronousKill, ENoCallback);
sl@0
   587
	TestKillWFAR(ENoCallback);
sl@0
   588
	TestKillInterrupt(ENoCallback);
sl@0
   589
	TestKernelContext();
sl@0
   590
	TestNaturalDeathContext();
sl@0
   591
#ifdef _DEBUG
sl@0
   592
	TestHwExcContext(EAsynchronousKill, ESpinningCallback);
sl@0
   593
	TestHwExcContext(EAsynchronousKill, ESleepingCallback);
sl@0
   594
	TestSwExcContext(EAsynchronousKill, ESpinningCallback);
sl@0
   595
	TestSwExcContext(EAsynchronousKill, ESleepingCallback);
sl@0
   596
	TestKillWFAR(ESpinningCallback);
sl@0
   597
	TestKillWFAR(ESleepingCallback);
sl@0
   598
	TestKillInterrupt(ESpinningCallback);
sl@0
   599
	TestKillInterrupt(ESleepingCallback);
sl@0
   600
#endif
sl@0
   601
sl@0
   602
	Channel.Close();
sl@0
   603
sl@0
   604
	// Wait for idle + async cleanup (waits for DKernelEventHandler to go away)
sl@0
   605
	r = UserSvr::HalFunction(EHalGroupKernel, EKernelHalSupervisorBarrier, (TAny*)5000, 0);
sl@0
   606
	test_KErrNone(r);
sl@0
   607
sl@0
   608
	__KHEAP_MARKEND;
sl@0
   609
sl@0
   610
	// Don't check user heap because if TLS is stored on the user-side this will not be freed when
sl@0
   611
	// the thread exits due to an exception.
sl@0
   612
sl@0
   613
	test.End();
sl@0
   614
	return 0;
sl@0
   615
	}