kernel/eka/nkern/arm/ncthrd.cpp
changeset 0 a41df078684a
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     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