os/kernelhwsrv/kernel/eka/nkern/arm/ncthrd.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 1994-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 // e32\nkern\arm\ncthrd.cpp
    15 // 
    16 //
    17 
    18 // NThreadBase member data
    19 #define __INCLUDE_NTHREADBASE_DEFINES__
    20 
    21 #define __INCLUDE_REG_OFFSETS__
    22 #include <arm.h>
    23 
    24 const TInt KNThreadMinStackSize = 0x100;	// needs to be enough for interrupt + reschedule stack
    25 
    26 // Called by a thread when it first runs
    27 extern void __StartThread();
    28 
    29 // Called by a thread which has been forced to exit
    30 // Interrupts off here, kernel unlocked
    31 extern void __DoForcedExit();
    32 
    33 void NThreadBase::SetEntry(NThreadFunction aFunc)
    34 	{
    35 	TUint32* sp=(TUint32*)iSavedSP;
    36 	sp[SP_R5]=(TUint32)aFunc;
    37 	}
    38 
    39 TInt NThread::Create(SNThreadCreateInfo& aInfo, TBool aInitial)
    40 	{
    41 	// Assert ParameterBlockSize is not negative and is a multiple of 8 bytes
    42 	__NK_ASSERT_ALWAYS((aInfo.iParameterBlockSize&0x80000007)==0);
    43 
    44 	__NK_ASSERT_ALWAYS(aInfo.iStackBase && aInfo.iStackSize>=aInfo.iParameterBlockSize+KNThreadMinStackSize);
    45 	TInt r=NThreadBase::Create(aInfo,aInitial);
    46 	if (r!=KErrNone)
    47 		return r;
    48 	if (!aInitial)
    49 		{
    50 		TUint32* sp=(TUint32*)(iStackBase+iStackSize-aInfo.iParameterBlockSize);
    51 		TUint32 r6=(TUint32)aInfo.iParameterBlock;
    52 		if (aInfo.iParameterBlockSize)
    53 			{
    54 			wordmove(sp,aInfo.iParameterBlock,aInfo.iParameterBlockSize);
    55 			r6=(TUint32)sp;
    56 			}
    57 		*--sp=(TUint32)__StartThread;		// PC
    58 		*--sp=0;							// R11
    59 		*--sp=0;							// R10
    60 		*--sp=0;							// R9
    61 		*--sp=0;							// R8
    62 		*--sp=0;							// R7
    63 		*--sp=r6;							// R6
    64 		*--sp=(TUint32)aInfo.iFunction;		// R5
    65 		*--sp=(TUint32)this;				// R4
    66 		*--sp=0x13;							// SPSR_SVC
    67 		*--sp=0;							// R14_USR
    68 		*--sp=0;							// R13_USR
    69 #ifdef __CPU_ARM_USE_DOMAINS
    70 		*--sp=Arm::DefaultDomainAccess;		// DACR
    71 #endif
    72 #ifdef __CPU_HAS_COPROCESSOR_ACCESS_REG
    73 		*--sp=Arm::DefaultCoprocessorAccess;	// CAR
    74 #endif
    75 #ifdef __CPU_HAS_VFP
    76 		*--sp=VFP_FPEXC_THRD_INIT;			// FPEXC
    77 #endif
    78 #ifdef __CPU_HAS_CP15_THREAD_ID_REG
    79 		*--sp=0;							// TID
    80 #endif
    81 #ifdef __CPU_SUPPORT_THUMB2EE
    82 		*--sp=0;							// ThumbEE Base
    83 #endif
    84 		iSavedSP=(TLinAddr)sp;
    85 		}
    86 	else
    87 		{
    88 #ifdef __CPU_HAS_COPROCESSOR_ACCESS_REG
    89 #ifdef __CPU_HAS_VFP
    90 #ifdef __CPU_XSCALE__
    91 		Arm::ModifyCar(0, 0x0c00);			// enable CP10, CP11
    92 #else
    93 		Arm::ModifyCar(0, 0x00f00000);		// full access to CP10, CP11
    94 #endif
    95 #endif
    96 		Arm::DefaultCoprocessorAccess = Arm::Car();
    97 #endif
    98 		NKern::EnableAllInterrupts();
    99 		}
   100 #ifdef BTRACE_THREAD_IDENTIFICATION
   101 	BTrace4(BTrace::EThreadIdentification,BTrace::ENanoThreadCreate,this);
   102 #endif
   103 	return KErrNone;
   104 	}
   105 
   106 /**	Called from generic layer when thread is killed asynchronously.
   107 
   108 	For ARM, save reason for last user->kernel switch (if any) so that user
   109 	context can be accessed from EDebugEventRemoveThread hook.  Must be done
   110 	before forcing the thread to exit as this alters the saved return address
   111 	which is used to figure out where the context is saved.
   112 
   113 	@pre kernel locked
   114 	@post kernel locked
   115  */
   116 
   117 void NThreadBase::OnKill()
   118 	{
   119 	if (iUserContextType != NThread::EContextNone)
   120 		{
   121 		NThread::TUserContextType t = ((NThread*)this)->UserContextType();
   122 		switch (t)
   123 			{
   124 		case NThread::EContextUserInterrupt:
   125 			t = NThread::EContextUserInterruptDied;
   126 			break;
   127 		case NThread::EContextSvsrInterrupt1:
   128 			t = NThread::EContextSvsrInterrupt1Died;
   129 			break;
   130 		case NThread::EContextSvsrInterrupt2:
   131 			t = NThread::EContextSvsrInterrupt2Died;
   132 			break;
   133 		case NThread::EContextWFAR:
   134 			t = NThread::EContextWFARDied;
   135 			break;
   136 		default:
   137 			// NOP
   138 			break;
   139 			}
   140 		iUserContextType = t;
   141 		}
   142 	}
   143 
   144 /**	Called from generic layer when thread exits.
   145 
   146 	For ARM, save that if the thread terminates synchronously the last
   147 	user->kernel switch was an exec call.  Do nothing if non-user thread or
   148 	reason already saved in OnKill().
   149 
   150 	@pre kernel locked
   151 	@post kernel locked
   152 	@see OnKill
   153  */
   154 
   155 void NThreadBase::OnExit()
   156 	{
   157 	CHECK_PRECONDITIONS(MASK_KERNEL_LOCKED,"NThreadBase::OnExit");				
   158 	if (iUserContextType == NThread::EContextUndefined)
   159 		iUserContextType = NThread::EContextExec;
   160 	}
   161 
   162 void NThreadBase::ForceExit()
   163 	{
   164 	TUint32* sp=(TUint32*)iSavedSP;
   165 	sp[SP_PC]=(TUint32)__DoForcedExit;
   166 	}
   167 
   168 void DumpExcInfo(TArmExcInfo& a)
   169 	{
   170 	DEBUGPRINT("Exc %1d Cpsr=%08x FAR=%08x FSR=%08x",a.iExcCode,a.iCpsr,a.iFaultAddress,a.iFaultStatus);
   171 	DEBUGPRINT(" R0=%08x  R1=%08x  R2=%08x  R3=%08x",a.iR0,a.iR1,a.iR2,a.iR3);
   172 	DEBUGPRINT(" R4=%08x  R5=%08x  R6=%08x  R7=%08x",a.iR4,a.iR5,a.iR6,a.iR7);
   173 	DEBUGPRINT(" R8=%08x  R9=%08x R10=%08x R11=%08x",a.iR8,a.iR9,a.iR10,a.iR11);
   174 	DEBUGPRINT("R12=%08x R13=%08x R14=%08x R15=%08x",a.iR12,a.iR13,a.iR14,a.iR15);
   175 	DEBUGPRINT("R13Svc=%08x R14Svc=%08x SpsrSvc=%08x",a.iR13Svc,a.iR14Svc,a.iSpsrSvc);
   176 	DEBUGPRINT("Thread %T, KernCSLocked=%d",TheScheduler.iCurrentThread,TheScheduler.iKernCSLocked);
   177 	}
   178 
   179 void DumpFullRegSet(SFullArmRegSet& a)
   180 	{
   181 	SNormalRegs& r = a.iN;
   182 	DEBUGPRINT("MODE_USR:");
   183 	DEBUGPRINT(" R0=%08x  R1=%08x  R2=%08x  R3=%08x", r.iR0,  r.iR1,  r.iR2,  r.iR3);
   184 	DEBUGPRINT(" R4=%08x  R5=%08x  R6=%08x  R7=%08x", r.iR4,  r.iR5,  r.iR6,  r.iR7);
   185 	DEBUGPRINT(" R8=%08x  R9=%08x R10=%08x R11=%08x", r.iR8,  r.iR9,  r.iR10, r.iR11);
   186 	DEBUGPRINT("R12=%08x R13=%08x R14=%08x R15=%08x", r.iR12, r.iR13, r.iR14, r.iR15);
   187 	DEBUGPRINT("CPSR=%08x", r.iFlags);
   188 	DEBUGPRINT("MODE_FIQ:");
   189 	DEBUGPRINT(" R8=%08x  R9=%08x R10=%08x R11=%08x",  r.iR8Fiq,  r.iR9Fiq,  r.iR10Fiq, r.iR11Fiq);
   190 	DEBUGPRINT("R12=%08x R13=%08x R14=%08x SPSR=%08x", r.iR12Fiq, r.iR13Fiq, r.iR14Fiq, r.iSpsrFiq);
   191 	DEBUGPRINT("MODE_IRQ:");
   192 	DEBUGPRINT("R13=%08x R14=%08x SPSR=%08x", r.iR13Irq, r.iR14Irq, r.iSpsrIrq);
   193 	DEBUGPRINT("MODE_SVC:");
   194 	DEBUGPRINT("R13=%08x R14=%08x SPSR=%08x", r.iR13Svc, r.iR14Svc, r.iSpsrSvc);
   195 	DEBUGPRINT("MODE_ABT:");
   196 	DEBUGPRINT("R13=%08x R14=%08x SPSR=%08x", r.iR13Abt, r.iR14Abt, r.iSpsrAbt);
   197 	DEBUGPRINT("MODE_UND:");
   198 	DEBUGPRINT("R13=%08x R14=%08x SPSR=%08x", r.iR13Und, r.iR14Und, r.iSpsrUnd);
   199 //	DEBUGPRINT("MODE_MON:");
   200 //	DEBUGPRINT("R13=%08x R14=%08x SPSR=%08x", r.iR13Mon, r.iR14Mon, r.iSpsrMon);
   201 
   202 	SAuxiliaryRegs& aux = a.iA;
   203 	DEBUGPRINT("TEEHBR=%08x  CPACR=%08x", aux.iTEEHBR, aux.iCPACR);
   204 
   205 	SBankedRegs& b = a.iB[0];
   206 	DEBUGPRINT(" SCTLR=%08x  ACTLR=%08x   PRRR=%08x   NMRR=%08x", b.iSCTLR, b.iACTLR, b.iPRRR, b.iNMRR);
   207 	DEBUGPRINT("  DACR=%08x  TTBR0=%08x  TTBR1=%08x  TTBCR=%08x", b.iDACR, b.iTTBR0, b.iTTBR1, b.iTTBCR);
   208 	DEBUGPRINT("  VBAR=%08x FCSEID=%08x CTXIDR=%08x", b.iVBAR, b.iFCSEIDR, b.iCTXIDR);
   209 	DEBUGPRINT("Thread ID     RWRW=%08x   RWRO=%08x   RWNO=%08x", b.iRWRWTID, b.iRWROTID, b.iRWNOTID);
   210 	DEBUGPRINT("  DFSR=%08x   DFAR=%08x   IFSR=%08x   IFAR=%08x", b.iDFSR, b.iDFAR, b.iIFSR, b.iIFAR);
   211 	DEBUGPRINT(" ADFSR=%08x              AIFSR=%08x", b.iADFSR, b.iAIFSR);
   212 #ifdef __CPU_HAS_VFP
   213 	DEBUGPRINT("FPEXC %08x", a.iMore[0]);
   214 #endif
   215 	DEBUGPRINT("ExcCode %08x", a.iExcCode);
   216 	}
   217 
   218 #define CONTEXT_ELEMENT_UNDEFINED(val)						\
   219 	{														\
   220 	TArmContextElement::EUndefined,							\
   221 	val														\
   222 	}
   223 
   224 #define CONTEXT_ELEMENT_EXCEPTION(reg)						\
   225 	{														\
   226 	TArmContextElement::EOffsetFromStackTop,				\
   227 	(- (-sizeof(TArmExcInfo)+_FOFF(TArmExcInfo,reg)) )>>2	\
   228 	}
   229 
   230 #define CONTEXT_ELEMENT_FROM_SP(offset)						\
   231 	{														\
   232 	TArmContextElement::EOffsetFromSp,						\
   233 	offset													\
   234 	}
   235 
   236 #define CONTEXT_ELEMENT_FROM_STACK_TOP(offset)				\
   237 	{														\
   238 	TArmContextElement::EOffsetFromStackTop,				\
   239 	offset													\
   240 	}
   241 
   242 #define CONTEXT_ELEMENT_SP_PLUS(offset)						\
   243 	{														\
   244 	TArmContextElement::ESpPlusOffset,						\
   245 	offset													\
   246 	}
   247 
   248 const TArmContextElement ContextTableException[] =
   249 	{
   250 	CONTEXT_ELEMENT_EXCEPTION(iR0),
   251 	CONTEXT_ELEMENT_EXCEPTION(iR1),
   252 	CONTEXT_ELEMENT_EXCEPTION(iR2),
   253 	CONTEXT_ELEMENT_EXCEPTION(iR3),
   254 	CONTEXT_ELEMENT_EXCEPTION(iR4),
   255 	CONTEXT_ELEMENT_EXCEPTION(iR5),
   256 	CONTEXT_ELEMENT_EXCEPTION(iR6),
   257 	CONTEXT_ELEMENT_EXCEPTION(iR7),
   258 	CONTEXT_ELEMENT_EXCEPTION(iR8),
   259 	CONTEXT_ELEMENT_EXCEPTION(iR9),
   260 	CONTEXT_ELEMENT_EXCEPTION(iR10),
   261 	CONTEXT_ELEMENT_EXCEPTION(iR11),
   262 	CONTEXT_ELEMENT_EXCEPTION(iR12),
   263 	CONTEXT_ELEMENT_EXCEPTION(iR13),
   264 	CONTEXT_ELEMENT_EXCEPTION(iR14),
   265 	CONTEXT_ELEMENT_EXCEPTION(iR15),
   266 	CONTEXT_ELEMENT_EXCEPTION(iCpsr),
   267 	CONTEXT_ELEMENT_UNDEFINED(0),
   268 	};
   269 
   270 const TArmContextElement ContextTableUndefined[] =
   271 	{
   272 	CONTEXT_ELEMENT_UNDEFINED(0),
   273 	CONTEXT_ELEMENT_UNDEFINED(0),
   274 	CONTEXT_ELEMENT_UNDEFINED(0),
   275 	CONTEXT_ELEMENT_UNDEFINED(0),
   276 	CONTEXT_ELEMENT_UNDEFINED(0),
   277 	CONTEXT_ELEMENT_UNDEFINED(0),
   278 	CONTEXT_ELEMENT_UNDEFINED(0),
   279 	CONTEXT_ELEMENT_UNDEFINED(0),
   280 	CONTEXT_ELEMENT_UNDEFINED(0),
   281 	CONTEXT_ELEMENT_UNDEFINED(0),
   282 	CONTEXT_ELEMENT_UNDEFINED(0),
   283 	CONTEXT_ELEMENT_UNDEFINED(0),
   284 	CONTEXT_ELEMENT_UNDEFINED(0),
   285 	CONTEXT_ELEMENT_UNDEFINED(0),
   286 	CONTEXT_ELEMENT_UNDEFINED(0),
   287 	CONTEXT_ELEMENT_UNDEFINED(0),
   288 	CONTEXT_ELEMENT_UNDEFINED(EUserMode),
   289 	CONTEXT_ELEMENT_UNDEFINED(0),
   290 	};
   291 
   292 // Table used for non dying threads which have been preempted by an interrupt
   293 // while in user mode.  
   294 
   295 const TArmContextElement ContextTableUserInterrupt[] =
   296 	{
   297 	CONTEXT_ELEMENT_FROM_STACK_TOP(6),
   298 	CONTEXT_ELEMENT_FROM_STACK_TOP(5),
   299 	CONTEXT_ELEMENT_FROM_STACK_TOP(4),
   300 	CONTEXT_ELEMENT_FROM_STACK_TOP(3),
   301 	CONTEXT_ELEMENT_FROM_SP(SP_R4),
   302 	CONTEXT_ELEMENT_FROM_SP(SP_R5),
   303 	CONTEXT_ELEMENT_FROM_SP(SP_R6),
   304 	CONTEXT_ELEMENT_FROM_SP(SP_R7),
   305 	CONTEXT_ELEMENT_FROM_SP(SP_R8),
   306 	CONTEXT_ELEMENT_FROM_SP(SP_R9),
   307 	CONTEXT_ELEMENT_FROM_SP(SP_R10),
   308 	CONTEXT_ELEMENT_FROM_SP(SP_R11),
   309 	CONTEXT_ELEMENT_FROM_STACK_TOP(2),
   310 	CONTEXT_ELEMENT_FROM_SP(SP_R13U),
   311 	CONTEXT_ELEMENT_FROM_SP(SP_R14U),
   312 	CONTEXT_ELEMENT_FROM_STACK_TOP(1),
   313 	CONTEXT_ELEMENT_FROM_STACK_TOP(8),		// interrupted CPSR
   314 	CONTEXT_ELEMENT_UNDEFINED(0),
   315 	};
   316 
   317 // Table used for threads which have been asynchronously killed after being
   318 // preempted by interrupt while in user mode.
   319 
   320 const TArmContextElement ContextTableUserInterruptDied[] =
   321 	{
   322 	CONTEXT_ELEMENT_FROM_STACK_TOP(6),
   323 	CONTEXT_ELEMENT_FROM_STACK_TOP(5),
   324 	CONTEXT_ELEMENT_FROM_STACK_TOP(4),
   325 	CONTEXT_ELEMENT_FROM_STACK_TOP(3),
   326 	CONTEXT_ELEMENT_UNDEFINED(0),
   327 	CONTEXT_ELEMENT_UNDEFINED(0),
   328 	CONTEXT_ELEMENT_UNDEFINED(0),
   329 	CONTEXT_ELEMENT_UNDEFINED(0),
   330 	CONTEXT_ELEMENT_UNDEFINED(0),
   331 	CONTEXT_ELEMENT_UNDEFINED(0),
   332 	CONTEXT_ELEMENT_UNDEFINED(0),
   333 	CONTEXT_ELEMENT_UNDEFINED(0),
   334 	CONTEXT_ELEMENT_FROM_STACK_TOP(2),
   335 	CONTEXT_ELEMENT_FROM_SP(SP_R13U),
   336 	CONTEXT_ELEMENT_FROM_SP(SP_R14U),
   337 	CONTEXT_ELEMENT_FROM_STACK_TOP(1),
   338 	CONTEXT_ELEMENT_FROM_STACK_TOP(8),		// interrupted CPSR
   339 	CONTEXT_ELEMENT_UNDEFINED(0),
   340 	};
   341 
   342 // Table used for threads which have been preempted by an interrupt while in
   343 // supervisor mode in the SWI handler either before the return address was
   344 // saved or after the registers were restored.
   345 
   346 const TArmContextElement ContextTableSvsrInterrupt1[] =
   347 	{
   348 	CONTEXT_ELEMENT_FROM_SP(SP_NEXT+USER_MEMORY_GUARD_SAVE_WORDS+2),
   349 	CONTEXT_ELEMENT_FROM_SP(SP_NEXT+USER_MEMORY_GUARD_SAVE_WORDS+3),
   350 	CONTEXT_ELEMENT_FROM_SP(SP_NEXT+USER_MEMORY_GUARD_SAVE_WORDS+4),
   351 	CONTEXT_ELEMENT_FROM_SP(SP_NEXT+USER_MEMORY_GUARD_SAVE_WORDS+5),
   352 	CONTEXT_ELEMENT_FROM_SP(SP_R4),
   353 	CONTEXT_ELEMENT_FROM_SP(SP_R5),
   354 	CONTEXT_ELEMENT_FROM_SP(SP_R6),
   355 	CONTEXT_ELEMENT_FROM_SP(SP_R7),
   356 	CONTEXT_ELEMENT_FROM_SP(SP_R8),
   357 	CONTEXT_ELEMENT_FROM_SP(SP_R9),
   358 	CONTEXT_ELEMENT_FROM_SP(SP_R10),
   359 	CONTEXT_ELEMENT_FROM_SP(SP_R11),
   360 	CONTEXT_ELEMENT_FROM_SP(SP_NEXT+USER_MEMORY_GUARD_SAVE_WORDS+6),
   361 	CONTEXT_ELEMENT_FROM_SP(SP_R13U),
   362 	CONTEXT_ELEMENT_FROM_SP(SP_R14U),
   363 	CONTEXT_ELEMENT_FROM_SP(SP_NEXT+USER_MEMORY_GUARD_SAVE_WORDS+6),  // r15 = r12
   364 	CONTEXT_ELEMENT_UNDEFINED(EUserMode),  // can't get flags so just use 'user mode'
   365 	CONTEXT_ELEMENT_UNDEFINED(0),
   366 	};
   367 
   368 // Table used for threads which have been asynchronously killed while in the situation
   369 // described above (see ContextTableSvsrInterrupt1).
   370 
   371 const TArmContextElement ContextTableSvsrInterrupt1Died[] =
   372 	{
   373 	CONTEXT_ELEMENT_UNDEFINED(0),
   374 	CONTEXT_ELEMENT_UNDEFINED(0),
   375 	CONTEXT_ELEMENT_UNDEFINED(0),
   376 	CONTEXT_ELEMENT_UNDEFINED(0),
   377 	CONTEXT_ELEMENT_UNDEFINED(0),
   378 	CONTEXT_ELEMENT_UNDEFINED(0),
   379 	CONTEXT_ELEMENT_UNDEFINED(0),
   380 	CONTEXT_ELEMENT_UNDEFINED(0),
   381 	CONTEXT_ELEMENT_UNDEFINED(0),
   382 	CONTEXT_ELEMENT_UNDEFINED(0),
   383 	CONTEXT_ELEMENT_UNDEFINED(0),
   384 	CONTEXT_ELEMENT_UNDEFINED(0),
   385 	CONTEXT_ELEMENT_UNDEFINED(0),
   386 	CONTEXT_ELEMENT_FROM_SP(SP_R13U),
   387 	CONTEXT_ELEMENT_FROM_SP(SP_R14U),
   388 	CONTEXT_ELEMENT_UNDEFINED(0),
   389 	CONTEXT_ELEMENT_UNDEFINED(EUserMode),  // can't get flags so just use 'user mode'
   390 	CONTEXT_ELEMENT_UNDEFINED(0),
   391 	};
   392 
   393 // Table used for threads which have been preempted by an interrupt while in
   394 // supervisor mode in the SWI handler after the return address was saved.
   395 
   396 const TArmContextElement ContextTableSvsrInterrupt2[] =
   397 	{
   398 	CONTEXT_ELEMENT_FROM_SP(SP_NEXT+USER_MEMORY_GUARD_SAVE_WORDS+2),
   399 	CONTEXT_ELEMENT_FROM_SP(SP_NEXT+USER_MEMORY_GUARD_SAVE_WORDS+3),
   400 	CONTEXT_ELEMENT_FROM_SP(SP_NEXT+USER_MEMORY_GUARD_SAVE_WORDS+4),
   401 	CONTEXT_ELEMENT_FROM_SP(SP_NEXT+USER_MEMORY_GUARD_SAVE_WORDS+5),
   402 	CONTEXT_ELEMENT_FROM_SP(SP_R4),
   403 	CONTEXT_ELEMENT_FROM_SP(SP_R5),
   404 	CONTEXT_ELEMENT_FROM_SP(SP_R6),
   405 	CONTEXT_ELEMENT_FROM_SP(SP_R7),
   406 	CONTEXT_ELEMENT_FROM_SP(SP_R8),
   407 	CONTEXT_ELEMENT_FROM_SP(SP_R9),
   408 	CONTEXT_ELEMENT_FROM_SP(SP_R10),
   409 	CONTEXT_ELEMENT_FROM_STACK_TOP(2),
   410 	CONTEXT_ELEMENT_FROM_SP(SP_NEXT+USER_MEMORY_GUARD_SAVE_WORDS+6),
   411 	CONTEXT_ELEMENT_FROM_SP(SP_R13U),
   412 	CONTEXT_ELEMENT_FROM_SP(SP_R14U),
   413 	CONTEXT_ELEMENT_FROM_STACK_TOP(1),
   414 	CONTEXT_ELEMENT_UNDEFINED(EUserMode),  // can't get flags so just use 'user mode'
   415 	CONTEXT_ELEMENT_UNDEFINED(0),
   416 	};
   417 
   418 // Table used for threads which have been asynchronously killed while in the situation
   419 // described above (see ContextTableSvsrInterrupt2).
   420 
   421 const TArmContextElement ContextTableSvsrInterrupt2Died[] =
   422 	{
   423 	CONTEXT_ELEMENT_UNDEFINED(0),
   424 	CONTEXT_ELEMENT_UNDEFINED(0),
   425 	CONTEXT_ELEMENT_UNDEFINED(0),
   426 	CONTEXT_ELEMENT_UNDEFINED(0),
   427 	CONTEXT_ELEMENT_UNDEFINED(0),
   428 	CONTEXT_ELEMENT_UNDEFINED(0),
   429 	CONTEXT_ELEMENT_UNDEFINED(0),
   430 	CONTEXT_ELEMENT_UNDEFINED(0),
   431 	CONTEXT_ELEMENT_UNDEFINED(0),
   432 	CONTEXT_ELEMENT_UNDEFINED(0),
   433 	CONTEXT_ELEMENT_UNDEFINED(0),
   434 	CONTEXT_ELEMENT_UNDEFINED(0),
   435 	CONTEXT_ELEMENT_UNDEFINED(0),
   436 	CONTEXT_ELEMENT_FROM_SP(SP_R13U),
   437 	CONTEXT_ELEMENT_FROM_SP(SP_R14U),
   438 	CONTEXT_ELEMENT_FROM_STACK_TOP(1),
   439 	CONTEXT_ELEMENT_UNDEFINED(EUserMode),  // can't get flags so just use 'user mode'
   440 	CONTEXT_ELEMENT_UNDEFINED(0),
   441 	};
   442 
   443 // Table used for non-dying threads blocked on their request semaphore.
   444 
   445 const TArmContextElement ContextTableWFAR[] =
   446 	{
   447 	CONTEXT_ELEMENT_UNDEFINED(0),
   448 	CONTEXT_ELEMENT_UNDEFINED(0),
   449 	CONTEXT_ELEMENT_UNDEFINED(0),
   450 	CONTEXT_ELEMENT_UNDEFINED(0),
   451 	CONTEXT_ELEMENT_FROM_SP(SP_R4),
   452 	CONTEXT_ELEMENT_FROM_SP(SP_R5),
   453 	CONTEXT_ELEMENT_FROM_SP(SP_R6),
   454 	CONTEXT_ELEMENT_FROM_SP(SP_R7),
   455 	CONTEXT_ELEMENT_FROM_SP(SP_R8),
   456 	CONTEXT_ELEMENT_FROM_SP(SP_R9),
   457 	CONTEXT_ELEMENT_FROM_SP(SP_R10),
   458 	CONTEXT_ELEMENT_FROM_STACK_TOP(2),
   459 	CONTEXT_ELEMENT_UNDEFINED(0),
   460 	CONTEXT_ELEMENT_FROM_SP(SP_R13U),
   461 	CONTEXT_ELEMENT_FROM_SP(SP_R14U),
   462 	CONTEXT_ELEMENT_FROM_STACK_TOP(1),
   463 	CONTEXT_ELEMENT_FROM_SP(SP_SPSR),
   464 	CONTEXT_ELEMENT_UNDEFINED(0),
   465 	};
   466 
   467 // Table used for threads killed asynchronously while blocked on their request
   468 // semaphore.
   469 
   470 const TArmContextElement ContextTableWFARDied[] =
   471 	{
   472 	CONTEXT_ELEMENT_UNDEFINED(0),
   473 	CONTEXT_ELEMENT_UNDEFINED(0),
   474 	CONTEXT_ELEMENT_UNDEFINED(0),
   475 	CONTEXT_ELEMENT_UNDEFINED(0),
   476 	CONTEXT_ELEMENT_UNDEFINED(0),
   477 	CONTEXT_ELEMENT_UNDEFINED(0),
   478 	CONTEXT_ELEMENT_UNDEFINED(0),
   479 	CONTEXT_ELEMENT_UNDEFINED(0),
   480 	CONTEXT_ELEMENT_UNDEFINED(0),
   481 	CONTEXT_ELEMENT_UNDEFINED(0),
   482 	CONTEXT_ELEMENT_UNDEFINED(0),
   483 	CONTEXT_ELEMENT_UNDEFINED(0),
   484 	CONTEXT_ELEMENT_UNDEFINED(0),
   485 	CONTEXT_ELEMENT_FROM_SP(SP_R13U),
   486 	CONTEXT_ELEMENT_FROM_SP(SP_R14U),
   487 	CONTEXT_ELEMENT_FROM_STACK_TOP(1),
   488 	CONTEXT_ELEMENT_FROM_SP(SP_SPSR),
   489 	CONTEXT_ELEMENT_UNDEFINED(0),
   490 	};
   491 
   492 const TArmContextElement ContextTableExec[] =
   493 	{
   494 	CONTEXT_ELEMENT_UNDEFINED(0),
   495 	CONTEXT_ELEMENT_UNDEFINED(0),
   496 	CONTEXT_ELEMENT_UNDEFINED(0),
   497 	CONTEXT_ELEMENT_FROM_STACK_TOP(10),
   498 	CONTEXT_ELEMENT_FROM_STACK_TOP(9),
   499 	CONTEXT_ELEMENT_FROM_STACK_TOP(8),
   500 	CONTEXT_ELEMENT_FROM_STACK_TOP(7),
   501 	CONTEXT_ELEMENT_FROM_STACK_TOP(6),
   502 	CONTEXT_ELEMENT_FROM_STACK_TOP(5),
   503 	CONTEXT_ELEMENT_FROM_STACK_TOP(4),
   504 	CONTEXT_ELEMENT_FROM_STACK_TOP(3),
   505 	CONTEXT_ELEMENT_FROM_STACK_TOP(2),
   506 	CONTEXT_ELEMENT_UNDEFINED(0),
   507 	CONTEXT_ELEMENT_FROM_SP(SP_R13U),
   508 	CONTEXT_ELEMENT_FROM_SP(SP_R14U),
   509 	CONTEXT_ELEMENT_FROM_STACK_TOP(1),
   510 	CONTEXT_ELEMENT_UNDEFINED(EUserMode),  // can't get flags so just use 'user mode'
   511 	CONTEXT_ELEMENT_UNDEFINED(0),
   512 	};
   513 
   514 // Table used to retrieve a thread's kernel side context.
   515 // Used for kernel threads.
   516 const TArmContextElement ContextTableKernel[] =
   517 	{
   518 	CONTEXT_ELEMENT_UNDEFINED(0),
   519 	CONTEXT_ELEMENT_UNDEFINED(0),
   520 	CONTEXT_ELEMENT_UNDEFINED(0),
   521 	CONTEXT_ELEMENT_UNDEFINED(0),
   522 	CONTEXT_ELEMENT_FROM_SP(SP_R4),			// r4 before reschedule
   523 	CONTEXT_ELEMENT_FROM_SP(SP_R5),			// r5 before reschedule
   524 	CONTEXT_ELEMENT_FROM_SP(SP_R6),			// r6 before reschedule
   525 	CONTEXT_ELEMENT_FROM_SP(SP_R7),			// r7 before reschedule
   526 	CONTEXT_ELEMENT_FROM_SP(SP_R8),			// r8 before reschedule
   527 	CONTEXT_ELEMENT_FROM_SP(SP_R9),			// r9 before reschedule
   528 	CONTEXT_ELEMENT_FROM_SP(SP_R10),		// r10 before reschedule
   529 	CONTEXT_ELEMENT_FROM_SP(SP_R11),		// r11 before reschedule
   530 	CONTEXT_ELEMENT_UNDEFINED(0),
   531 	CONTEXT_ELEMENT_SP_PLUS(SP_NEXT),		// supervisor stack pointer before reschedule
   532 	CONTEXT_ELEMENT_UNDEFINED(0),			// supervisor lr is unknown
   533 	CONTEXT_ELEMENT_FROM_SP(SP_PC),			// return address from reschedule
   534 	CONTEXT_ELEMENT_UNDEFINED(ESvcMode),	// can't get flags so just use 'supervisor mode'
   535 	CONTEXT_ELEMENT_UNDEFINED(0),
   536 	};
   537 
   538 // Table used for non dying threads which are in a user callback while returning
   539 // from having been preempted by an interrupt while in user mode.  
   540 
   541 const TArmContextElement ContextTableUserIntrCallback[] =
   542 	{
   543 	CONTEXT_ELEMENT_FROM_STACK_TOP(6),
   544 	CONTEXT_ELEMENT_FROM_STACK_TOP(5),
   545 	CONTEXT_ELEMENT_FROM_STACK_TOP(4),
   546 	CONTEXT_ELEMENT_FROM_STACK_TOP(3),
   547 	CONTEXT_ELEMENT_FROM_STACK_TOP(8+USER_MEMORY_GUARD_SAVE_WORDS+9),
   548 	CONTEXT_ELEMENT_FROM_STACK_TOP(8+USER_MEMORY_GUARD_SAVE_WORDS+8),
   549 	CONTEXT_ELEMENT_FROM_STACK_TOP(8+USER_MEMORY_GUARD_SAVE_WORDS+7),
   550 	CONTEXT_ELEMENT_FROM_STACK_TOP(8+USER_MEMORY_GUARD_SAVE_WORDS+6),
   551 	CONTEXT_ELEMENT_FROM_STACK_TOP(8+USER_MEMORY_GUARD_SAVE_WORDS+5),
   552 	CONTEXT_ELEMENT_FROM_STACK_TOP(8+USER_MEMORY_GUARD_SAVE_WORDS+4),
   553 	CONTEXT_ELEMENT_FROM_STACK_TOP(8+USER_MEMORY_GUARD_SAVE_WORDS+3),
   554 	CONTEXT_ELEMENT_FROM_STACK_TOP(8+USER_MEMORY_GUARD_SAVE_WORDS+2),
   555 	CONTEXT_ELEMENT_FROM_STACK_TOP(2),
   556 	CONTEXT_ELEMENT_FROM_SP(SP_R13U),
   557 	CONTEXT_ELEMENT_FROM_SP(SP_R14U),
   558 	CONTEXT_ELEMENT_FROM_STACK_TOP(1),
   559 	CONTEXT_ELEMENT_FROM_STACK_TOP(8),		// interrupted CPSR
   560 	CONTEXT_ELEMENT_UNDEFINED(0),
   561 	};
   562 
   563 // Table used for non-dying threads which are in a user callback while returning
   564 // from being blocked on their request semaphore.
   565 
   566 const TArmContextElement ContextTableWFARCallback[] =
   567 	{
   568 	CONTEXT_ELEMENT_UNDEFINED(0),
   569 	CONTEXT_ELEMENT_UNDEFINED(0),
   570 	CONTEXT_ELEMENT_UNDEFINED(0),
   571 	CONTEXT_ELEMENT_UNDEFINED(0),
   572 	CONTEXT_ELEMENT_FROM_STACK_TOP(11),
   573 	CONTEXT_ELEMENT_FROM_STACK_TOP(10),
   574 	CONTEXT_ELEMENT_FROM_STACK_TOP(9),
   575 	CONTEXT_ELEMENT_FROM_STACK_TOP(8),
   576 	CONTEXT_ELEMENT_FROM_STACK_TOP(7),
   577 	CONTEXT_ELEMENT_FROM_STACK_TOP(6),
   578 	CONTEXT_ELEMENT_FROM_STACK_TOP(5),
   579 	CONTEXT_ELEMENT_FROM_STACK_TOP(2),
   580 	CONTEXT_ELEMENT_UNDEFINED(0),
   581 	CONTEXT_ELEMENT_FROM_SP(SP_R13U),
   582 	CONTEXT_ELEMENT_FROM_SP(SP_R14U),
   583 	CONTEXT_ELEMENT_FROM_STACK_TOP(1),
   584 	CONTEXT_ELEMENT_FROM_SP(SP_SPSR),
   585 	CONTEXT_ELEMENT_UNDEFINED(0),
   586 	};
   587 
   588 const TArmContextElement* const ThreadUserContextTables[] =
   589 	{
   590 	ContextTableUndefined, // EContextNone
   591 	ContextTableException,
   592 	ContextTableUndefined,
   593 	ContextTableUserInterrupt,
   594 	ContextTableUserInterruptDied,
   595 	ContextTableSvsrInterrupt1,
   596 	ContextTableSvsrInterrupt1Died,
   597 	ContextTableSvsrInterrupt2,
   598 	ContextTableSvsrInterrupt2Died,
   599 	ContextTableWFAR,
   600 	ContextTableWFARDied,
   601 	ContextTableExec,
   602 	ContextTableKernel,
   603 	ContextTableUserIntrCallback,
   604 	ContextTableWFARCallback,
   605 	0 // Null terminated
   606 	};
   607 
   608 /**  Return table of pointers to user context tables.
   609 
   610 	Each user context table is an array of TArmContextElement objects, one per
   611 	ARM CPU register, in the order defined in TArmRegisters.
   612 
   613 	The master table contains pointers to the user context tables in the order
   614 	defined in TUserContextType.  There are as many user context tables as
   615 	scenarii leading a user thread to switch to privileged mode.
   616 
   617 	Stop-mode debug agents should use this function to store the address of the
   618 	master table at a location known to the host debugger.  Run-mode debug
   619 	agents are advised to use NKern::GetUserContext() and
   620 	NKern::SetUserContext() instead.
   621 
   622 	@return A pointer to the master table.  The master table is NULL
   623 	terminated.  The master and user context tables are guaranteed to remain at
   624 	the same location for the lifetime of the OS execution so it is safe the
   625 	cache the returned address.
   626 
   627 	@see UserContextType
   628 	@see TArmContextElement
   629 	@see TArmRegisters
   630 	@see TUserContextType
   631 	@see NKern::SetUserContext
   632 	@see NKern::GetUserContext
   633 
   634 	@publishedPartner
   635  */
   636 EXPORT_C const TArmContextElement* const* NThread::UserContextTables()
   637 	{
   638 	return &ThreadUserContextTables[0];
   639 	}
   640 
   641 
   642 #ifndef __USER_CONTEXT_TYPE_MACHINE_CODED__
   643 extern TBool RescheduledAfterInterrupt(TUint32 /*aAddr*/);
   644 
   645 /** Get a value which indicates where a thread's user mode context is stored.
   646 
   647 	@return A value that can be used as an index into the tables returned by
   648 	NThread::UserContextTables().
   649 
   650 	@pre any context
   651 	@pre kernel locked
   652 	@post kernel locked
   653  
   654 	@see UserContextTables
   655 	@publishedPartner
   656  */
   657 EXPORT_C NThread::TUserContextType NThread::UserContextType()
   658 	{
   659 	CHECK_PRECONDITIONS(MASK_KERNEL_LOCKED,"NThread::UserContextType");				
   660 	// Dying thread? use context saved earlier by kernel
   661 	if (iCsFunction == ECSExitInProgress)
   662 		return (TUserContextType)iUserContextType;
   663 
   664 	// Check for EContextNone and EContextException
   665 	// Also EContextUserIntrCallback and EContextWFARCallback
   666 	if(iUserContextType<=EContextException || iUserContextType==EContextUserIntrCallback
   667 			|| iUserContextType==EContextWFARCallback)
   668 		return (TUserContextType)iUserContextType;
   669 
   670 	// Getting current thread context? must be in exec call as exception
   671 	// and dying thread cases were tested above.
   672 	if (this == NCurrentThread())
   673 		return EContextExec;
   674 
   675 	// Check what caused the thread to enter supervisor mode
   676 	TUint32* sst=(TUint32*)((TUint32)iStackBase+(TUint32)iStackSize);
   677 	TUint32* sp=(TUint32*)iSavedSP;		// saved supervisor stack pointer
   678 	TInt n=sst-sp;						// number of words on the supervisor stack
   679 	TUint32 resched_ret=sp[SP_PC];		// return address from reschedule
   680 	if (RescheduledAfterInterrupt(resched_ret))
   681 		{
   682 		// thread was preempted due to an interrupt
   683 		// interrupt and reschedule will have pushed 20+EXTRA words onto the stack
   684 		if ((sp[SP_NEXT]&EMaskMode)==EUserMode)   // interrupted mode = user?
   685 			return NThread::EContextUserInterrupt;
   686 		if (n<(30+EXTRA_WORDS))	// n<30 if interrupt occurred in exec call entry before r3-r10 saved
   687 			{					// or after r3-r10 restored
   688 			if (n==(20+EXTRA_WORDS))
   689 				{
   690 				// interrupt before return address, r11 were saved or after registers restored
   691 				return EContextSvsrInterrupt1;
   692 				}
   693 			else
   694 				{
   695 				// interrupt after return address, r11 saved
   696 				return EContextSvsrInterrupt2;
   697 				}
   698 			}
   699 		// thread was interrupted in supervisor mode
   700 		// return address and r3-r11 were saved
   701 		}
   702 
   703 	// Transition to supervisor mode must have been due to a SWI
   704 	if (n==(15+EXTRA_WORDS))
   705 		{
   706 		// thread must have blocked doing Exec::WaitForAnyRequest
   707 		return EContextWFAR;
   708 		}
   709 
   710 	// Thread must have been in a SLOW or UNPROTECTED Exec call
   711 	return EContextExec;
   712 	}
   713 
   714 #endif // __USER_CONTEXT_TYPE_MACHINE_CODED__
   715 
   716 // Enter and return with kernel locked
   717 void NThread::GetContext(TArmRegSet& aContext, TUint32& aAvailRegistersMask, const TArmContextElement* aContextTable)
   718 	{
   719 	TUint32* sp  = (TUint32*)iSavedSP;
   720 	TUint32* st  = (TUint32*)((TUint32)iStackBase+(TUint32)iStackSize);
   721 	TArmReg* out = (TArmReg*)(&aContext);
   722 	TBool currentThread = (NCurrentThread() == this);
   723 	
   724 	aAvailRegistersMask = 0;
   725 	if (iNState == EDead)
   726 		{// This thread's stack may no longer exist so just exit.
   727 		return;
   728 		}
   729 
   730 	// Copy available context into provided structure.
   731 	for (TInt i = 0; i<KArmRegisterCount; ++i)
   732 		{
   733 		TInt v = aContextTable[i].iValue;
   734 		TInt t = aContextTable[i].iType;
   735 		if(!currentThread && t==TArmContextElement::EOffsetFromSp) 
   736 			{
   737 			// thread has been preempted, it is safe to fetch its context
   738 			// from the info saved in Reschedule().
   739 			v = sp[v];
   740 			aAvailRegistersMask |= (1<<i);
   741 			}
   742 		else if(t==TArmContextElement::EOffsetFromStackTop)
   743 			{
   744 			v = st[-v];
   745 			aAvailRegistersMask |= (1<<i);
   746 			}
   747 		else if(!currentThread && t==TArmContextElement::ESpPlusOffset)
   748 			{
   749 			v = (TInt)(sp+v);
   750 			aAvailRegistersMask |= (1<<i);
   751 			}
   752 		out[i] = v;
   753 		}
   754 
   755 	// Getting context of current thread? some values can be fetched directly
   756 	// from the registers if they are not available from the stack.
   757 	if (currentThread && aContextTable[EArmSp].iType == TArmContextElement::EOffsetFromSp)
   758 		{
   759 		Arm::GetUserSpAndLr(out+EArmSp);
   760 		aAvailRegistersMask |= (1<<EArmSp) | (1<<EArmLr);
   761 		}
   762 	}
   763 
   764 // Enter and return with kernel locked
   765 void NThread::GetUserContext(TArmRegSet& aContext, TUint32& aAvailRegistersMask)
   766 	{
   767 	TUserContextType type=UserContextType();
   768 	NThread::GetContext(aContext, aAvailRegistersMask, UserContextTables()[type]);
   769 	}
   770 
   771 // Enter and return with kernel locked
   772 void NThread::GetSystemContext(TArmRegSet& aContext, TUint32& aAvailRegistersMask)
   773 	{
   774 	NThread::GetContext(aContext, aAvailRegistersMask, UserContextTables()[EContextKernel]);
   775 	}
   776 
   777 // Enter and return with kernel locked
   778 void NThread::SetUserContext(const TArmRegSet& aContext)
   779 	{
   780 	if (iNState == EDead)
   781 		{// This thread's stack may no longer exist so just exit.
   782 		return;
   783 		}
   784 	TUserContextType type=UserContextType();
   785 	const TArmContextElement* c = NThread::UserContextTables()[type];
   786 	TUint32* sp  = (TUint32*)iSavedSP;
   787 	TUint32* st  = (TUint32*)((TUint32)iStackBase+(TUint32)iStackSize);
   788 	TArmReg* in = (TArmReg*)(&aContext);
   789 	TBool currentThread = (NCurrentThread() == this);
   790 
   791 	// Check that target thread is in USR mode, and update only the flags part of the PSR
   792 	TUint32 tFlags = 0;
   793 	TUint32* tFlagsPtr = &tFlags;
   794 	TUint32 flagsCtxValue = c[EArmFlags].iValue;
   795 	switch (c[EArmFlags].iType)						// describes how to interpret flagsCtxValue
   796 	{
   797 	case TArmContextElement::EUndefined:
   798 		// Flags register not saved; not necessarily an error, but we can't update the flags
   799 		tFlags = flagsCtxValue;						// use mode bits of flagsCtxValue itself
   800 		break;
   801 
   802 	case TArmContextElement::EOffsetFromStackTop:
   803 		// Flags register saved, flagsCtxValue is offset from ToS
   804 		tFlagsPtr = &st[-flagsCtxValue];
   805 		break;
   806 
   807 	case TArmContextElement::EOffsetFromSp:
   808 		// Flags register saved, flagsCtxValue is offset from SP
   809 		if (!currentThread)
   810 			tFlagsPtr = &sp[flagsCtxValue];
   811 		else
   812 			{
   813 			// This can only occur when the thread is exiting. Therefore,
   814 			// we allow it, but the changed values will never be used.
   815 			tFlags = 0x10;
   816 			}
   817 		break;
   818 
   819 	default:
   820 		// Assertion below will fail with default value ...
   821 		;
   822 	}
   823 
   824 	tFlags = *tFlagsPtr;							// retrieve saved flags
   825 	__NK_ASSERT_ALWAYS((tFlags & 0x1f) == 0x10);	// target thread must be in USR mode
   826 	const TUint32 writableFlags = 0xF80F0000;		// NZCVQ.......GE3-0................
   827 	tFlags &= ~writableFlags;
   828 	tFlags |= in[EArmFlags] & writableFlags;
   829 	*tFlagsPtr = tFlags;							// update saved flags
   830 
   831 	// Copy provided context into stack if possible
   832 	for (TInt i = 0; i<KArmRegisterCount; ++i)
   833 		{
   834 		// The Flags were already processed above, and we don't allow
   835 		// changing the DACR, so we can just skip these two index values
   836 		if (i == EArmFlags || i == EArmDacr)
   837 			continue;
   838 
   839 		TInt v = c[i].iValue;
   840 		TInt t = c[i].iType;
   841 		if(!currentThread && t==TArmContextElement::EOffsetFromSp) 
   842 			{
   843 			// thread has been preempted, it is safe to change context
   844 			// saved in Reschedule().
   845 			sp[v] = in[i];
   846 			}
   847 		if(t==TArmContextElement::EOffsetFromStackTop)
   848 			st[-v] = in[i];
   849 		}
   850 
   851 	// Current thread? some values can be loaded straight into the registers
   852 	// if they haven't been stored on the stack yet.
   853 	if (currentThread && c[EArmSp].iType == TArmContextElement::EOffsetFromSp)
   854 		Arm::SetUserSpAndLr(in+EArmSp);
   855 	}
   856 
   857 // Modify a non-running thread's user stack pointer
   858 // Enter and return with kernel locked
   859 void NThread::ModifyUsp(TLinAddr aUsp)
   860 	{
   861 	// Check what caused the thread to enter supervisor mode
   862 	TUint32* sst=(TUint32*)((TUint32)iStackBase+(TUint32)iStackSize);
   863 	if (iSpare3)
   864 		{
   865 		// exception caused transition to supervisor mode
   866 		TArmExcInfo& e=((TArmExcInfo*)sst)[-1];
   867 		e.iR13=aUsp;
   868 		return;
   869 		}
   870 	TUint32* sp=(TUint32*)iSavedSP;		// saved supervisor stack pointer
   871 	sp[SP_R13U]=aUsp;
   872 	}
   873 
   874 /** Get (subset of) user context of specified thread.
   875 
   876 	The nanokernel does not systematically save all registers in the supervisor
   877 	stack on entry into privileged mode and the exact subset depends on why the
   878 	switch to privileged mode occured.  So in general only a subset of the
   879 	register set is available.
   880 
   881 	@param aThread	Thread to inspect.  It can be the current thread or a
   882 	non-current one.
   883 
   884 	@param aContext	Pointer to TArmRegSet structure where the context is
   885 	copied.
   886 
   887 	@param aAvailRegistersMask Bit mask telling which subset of the context is
   888 	available and has been copied to aContext (1: register available / 0: not
   889 	available).  Bit 0 stands for register R0.
   890 
   891 	@see TArmRegSet
   892 	@see ThreadSetUserContext
   893 
   894 	@pre Call in a thread context.
   895 	@pre Interrupts must be enabled.
   896  */
   897 EXPORT_C void NKern::ThreadGetUserContext(NThread* aThread, TAny* aContext, TUint32& aAvailRegistersMask)
   898 	{
   899 	CHECK_PRECONDITIONS(MASK_INTERRUPTS_ENABLED|MASK_NOT_ISR|MASK_NOT_IDFC,"NKern::ThreadGetUserContext");
   900 	TArmRegSet& a=*(TArmRegSet*)aContext;
   901 	memclr(aContext, sizeof(TArmRegSet));
   902 	NKern::Lock();
   903 	aThread->GetUserContext(a, aAvailRegistersMask);
   904 	NKern::Unlock();
   905 	}
   906 
   907 /** Get (subset of) system context of specified thread.
   908   
   909 	@param aThread	Thread to inspect.  It can be the current thread or a
   910 	non-current one.
   911 
   912 	@param aContext	Pointer to TArmRegSet structure where the context is
   913 	copied.
   914 
   915 	@param aAvailRegistersMask Bit mask telling which subset of the context is
   916 	available and has been copied to aContext (1: register available / 0: not
   917 	available).  Bit 0 stands for register R0.
   918 
   919 	@see TArmRegSet
   920 	@see ThreadSetUserContext
   921 
   922 	@pre Call in a thread context.
   923 	@pre Interrupts must be enabled.
   924  */
   925 EXPORT_C void NKern::ThreadGetSystemContext(NThread* aThread, TAny* aContext, TUint32& aAvailRegistersMask)
   926 	{
   927 	CHECK_PRECONDITIONS(MASK_INTERRUPTS_ENABLED|MASK_NOT_ISR|MASK_NOT_IDFC,"NKern::ThreadGetSystemContext");
   928 	TArmRegSet& a=*(TArmRegSet*)aContext;
   929 	memclr(aContext, sizeof(TArmRegSet));
   930 	NKern::Lock();
   931 	aThread->GetSystemContext(a, aAvailRegistersMask);
   932 	NKern::Unlock();
   933 	}
   934 
   935 /** Set (subset of) user context of specified thread.
   936 
   937 	@param aThread	Thread to modify.  It can be the current thread or a
   938 	non-current one.
   939 
   940 	@param aContext	Pointer to TArmRegSet structure containing the context
   941 	to set.  The values of registers which aren't part of the context saved
   942 	on the supervisor stack are ignored.
   943 
   944 	@see TArmRegSet
   945 	@see ThreadGetUserContext
   946 
   947   	@pre Call in a thread context.
   948 	@pre Interrupts must be enabled.
   949  */
   950 EXPORT_C void NKern::ThreadSetUserContext(NThread* aThread, TAny* aContext)
   951 	{
   952 	CHECK_PRECONDITIONS(MASK_INTERRUPTS_ENABLED|MASK_NOT_ISR|MASK_NOT_IDFC,"NKern::ThreadSetUserContext");
   953 	TArmRegSet& a=*(TArmRegSet*)aContext;
   954 	NKern::Lock();
   955 	aThread->SetUserContext(a);
   956 	NKern::Unlock();
   957 	}
   958 
   959 /** @internalComponent */
   960 void NKern::ThreadModifyUsp(NThread* aThread, TLinAddr aUsp)
   961 	{
   962 	NKern::Lock();
   963 	aThread->ModifyUsp(aUsp);
   964 	NKern::Unlock();
   965 	}
   966 
   967 #ifdef __CPU_ARM_USE_DOMAINS
   968 TUint32 NThread::Dacr()
   969 	{
   970 	if (this==TheScheduler.iCurrentThread)
   971 		return Arm::Dacr();
   972 	NKern::Lock();
   973 	TUint32* sp=(TUint32*)iSavedSP;		// saved supervisor stack pointer
   974 	TUint32 dacr=sp[SP_DACR];
   975 	NKern::Unlock();
   976 	return dacr;
   977 	}
   978 
   979 void NThread::SetDacr(TUint32 aDacr)
   980 	{
   981 	if (this==TheScheduler.iCurrentThread)
   982 		Arm::SetDacr(aDacr);
   983 	NKern::Lock();
   984 	TUint32* sp=(TUint32*)iSavedSP;		// saved supervisor stack pointer
   985 	sp[SP_DACR]=aDacr;
   986 	NKern::Unlock();
   987 	}
   988 
   989 TUint32 NThread::ModifyDacr(TUint32 aClearMask, TUint32 aSetMask)
   990 	{
   991 	if (this==TheScheduler.iCurrentThread)
   992 		return Arm::ModifyDacr(aClearMask,aSetMask);
   993 	NKern::Lock();
   994 	TUint32* sp=(TUint32*)iSavedSP;		// saved supervisor stack pointer
   995 	TUint32 dacr=sp[SP_DACR];
   996 	sp[SP_DACR]=(dacr&~aClearMask)|aSetMask;
   997 	NKern::Unlock();
   998 	return dacr;
   999 	}
  1000 #endif
  1001 
  1002 #ifdef __CPU_HAS_COPROCESSOR_ACCESS_REG
  1003 void NThread::SetCar(TUint32 aCar)
  1004 	{
  1005 	if (this==TheScheduler.iCurrentThread)
  1006 		Arm::SetCar(aCar);
  1007 	NKern::Lock();
  1008 	TUint32* sp=(TUint32*)iSavedSP;		// saved supervisor stack pointer
  1009 	sp[SP_CAR]=aCar;
  1010 	NKern::Unlock();
  1011 	}
  1012 #endif
  1013 
  1014 
  1015 
  1016 /** Get the saved coprocessor access register value for a thread
  1017 
  1018 @return The saved value of the CAR, 0 if CPU doesn't have CAR
  1019 @pre	Don't call from ISR
  1020 
  1021 @publishedPartner
  1022 @released
  1023  */
  1024 EXPORT_C TUint32 NThread::Car()
  1025 	{
  1026 	CHECK_PRECONDITIONS(MASK_NOT_ISR,"NThread::Car");				
  1027 #ifdef __CPU_HAS_COPROCESSOR_ACCESS_REG
  1028 	if (this==TheScheduler.iCurrentThread)
  1029 		return Arm::Car();
  1030 	NKern::Lock();
  1031 	TUint32* sp=(TUint32*)iSavedSP;		// saved supervisor stack pointer
  1032 	TUint32 car=sp[SP_CAR];
  1033 	NKern::Unlock();
  1034 	return car;
  1035 #else
  1036 	return 0;
  1037 #endif
  1038 	}
  1039 
  1040 
  1041 
  1042 /** Modify the saved coprocessor access register value for a thread
  1043 	Does nothing if CPU does not have CAR.
  1044 
  1045 @param	aClearMask	Mask of bits to clear	(1 = clear this bit)
  1046 @param	aSetMask	Mask of bits to set		(1 = set this bit)
  1047 @return The original saved value of the CAR, 0 if CPU doesn't have CAR
  1048 @pre	Don't call from ISR
  1049 
  1050 @publishedPartner
  1051 @released
  1052  */
  1053 EXPORT_C TUint32 NThread::ModifyCar(TUint32 aClearMask, TUint32 aSetMask)
  1054 	{
  1055 	CHECK_PRECONDITIONS(MASK_NOT_ISR,"NThread::ModifyCar");				
  1056 #ifdef __CPU_HAS_COPROCESSOR_ACCESS_REG
  1057 	if (this==TheScheduler.iCurrentThread)
  1058 		return Arm::ModifyCar(aClearMask,aSetMask);
  1059 	NKern::Lock();
  1060 	TUint32* sp=(TUint32*)iSavedSP;		// saved supervisor stack pointer
  1061 	TUint32 car=sp[SP_CAR];
  1062 	sp[SP_CAR]=(car&~aClearMask)|aSetMask;
  1063 	NKern::Unlock();
  1064 	return car;
  1065 #else
  1066 	return 0;
  1067 #endif
  1068 	}
  1069 
  1070 #ifdef __CPU_HAS_VFP
  1071 void NThread::SetFpExc(TUint32 aVal)
  1072 	{
  1073 	if (this==TheScheduler.iCurrentThread)
  1074 		Arm::SetFpExc(aVal);
  1075 	NKern::Lock();
  1076 	TUint32* sp=(TUint32*)iSavedSP;		// saved supervisor stack pointer
  1077 	sp[SP_FPEXC]=aVal;
  1078 	NKern::Unlock();
  1079 	}
  1080 #endif
  1081 
  1082 
  1083 
  1084 /** Get the saved VFP FPEXC register value for a thread
  1085 
  1086 @return The saved value of FPEXC, 0 if VFP not present
  1087 @pre	Don't call from ISR
  1088 
  1089 @publishedPartner
  1090 @released
  1091  */
  1092 EXPORT_C TUint32 NThread::FpExc()
  1093 	{
  1094 	CHECK_PRECONDITIONS(MASK_NOT_ISR,"NThread::FpExc");				
  1095 #ifdef __CPU_HAS_VFP
  1096 	if (this==TheScheduler.iCurrentThread)
  1097 		return Arm::FpExc();
  1098 	NKern::Lock();
  1099 	TUint32* sp=(TUint32*)iSavedSP;		// saved supervisor stack pointer
  1100 	TUint32 r=sp[SP_FPEXC];
  1101 	NKern::Unlock();
  1102 	return r;
  1103 #else
  1104 	return 0;
  1105 #endif
  1106 	}
  1107 
  1108 
  1109 
  1110 /** Modify the saved VFP FPEXC register value for a thread
  1111 	Does nothing if VFP not present
  1112 
  1113 @param	aClearMask	Mask of bits to clear	(1 = clear this bit)
  1114 @param	aSetMask	Mask of bits to set		(1 = set this bit)
  1115 @return The original saved value of FPEXC, 0 if VFP not present
  1116 @pre	Don't call from ISR
  1117 
  1118 @publishedPartner
  1119 @released
  1120  */
  1121 EXPORT_C TUint32 NThread::ModifyFpExc(TUint32 aClearMask, TUint32 aSetMask)
  1122 	{
  1123 	CHECK_PRECONDITIONS(MASK_NOT_ISR,"NThread::ModifyFpExc");				
  1124 #ifdef __CPU_HAS_VFP
  1125 	if (this==TheScheduler.iCurrentThread)
  1126 		return Arm::ModifyFpExc(aClearMask,aSetMask);
  1127 	NKern::Lock();
  1128 	TUint32* sp=(TUint32*)iSavedSP;		// saved supervisor stack pointer
  1129 	TUint32 r=sp[SP_FPEXC];
  1130 	sp[SP_FPEXC]=(r&~aClearMask)|aSetMask;
  1131 	NKern::Unlock();
  1132 	return r;
  1133 #else
  1134 	return 0;
  1135 #endif
  1136 	}
  1137