First public contribution.
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".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // e32\nkern\arm\ncthrd.cpp
18 // NThreadBase member data
19 #define __INCLUDE_NTHREADBASE_DEFINES__
21 #define __INCLUDE_REG_OFFSETS__
24 const TInt KNThreadMinStackSize = 0x100; // needs to be enough for interrupt + reschedule stack
26 // Called by a thread when it first runs
27 extern void __StartThread();
29 // Called by a thread which has been forced to exit
30 // Interrupts off here, kernel unlocked
31 extern void __DoForcedExit();
33 void NThreadBase::SetEntry(NThreadFunction aFunc)
35 TUint32* sp=(TUint32*)iSavedSP;
36 sp[SP_R5]=(TUint32)aFunc;
39 TInt NThread::Create(SNThreadCreateInfo& aInfo, TBool aInitial)
41 // Assert ParameterBlockSize is not negative and is a multiple of 8 bytes
42 __NK_ASSERT_ALWAYS((aInfo.iParameterBlockSize&0x80000007)==0);
44 __NK_ASSERT_ALWAYS(aInfo.iStackBase && aInfo.iStackSize>=aInfo.iParameterBlockSize+KNThreadMinStackSize);
45 TInt r=NThreadBase::Create(aInfo,aInitial);
50 TUint32* sp=(TUint32*)(iStackBase+iStackSize-aInfo.iParameterBlockSize);
51 TUint32 r6=(TUint32)aInfo.iParameterBlock;
52 if (aInfo.iParameterBlockSize)
54 wordmove(sp,aInfo.iParameterBlock,aInfo.iParameterBlockSize);
57 *--sp=(TUint32)__StartThread; // PC
64 *--sp=(TUint32)aInfo.iFunction; // R5
65 *--sp=(TUint32)this; // R4
66 *--sp=0x13; // SPSR_SVC
69 #ifdef __CPU_ARM_USE_DOMAINS
70 *--sp=Arm::DefaultDomainAccess; // DACR
72 #ifdef __CPU_HAS_COPROCESSOR_ACCESS_REG
73 *--sp=Arm::DefaultCoprocessorAccess; // CAR
76 *--sp=VFP_FPEXC_THRD_INIT; // FPEXC
78 #ifdef __CPU_HAS_CP15_THREAD_ID_REG
81 #ifdef __CPU_SUPPORT_THUMB2EE
82 *--sp=0; // ThumbEE Base
84 iSavedSP=(TLinAddr)sp;
88 #ifdef __CPU_HAS_COPROCESSOR_ACCESS_REG
91 Arm::ModifyCar(0, 0x0c00); // enable CP10, CP11
93 Arm::ModifyCar(0, 0x00f00000); // full access to CP10, CP11
96 Arm::DefaultCoprocessorAccess = Arm::Car();
98 NKern::EnableAllInterrupts();
100 #ifdef BTRACE_THREAD_IDENTIFICATION
101 BTrace4(BTrace::EThreadIdentification,BTrace::ENanoThreadCreate,this);
106 /** Called from generic layer when thread is killed asynchronously.
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.
117 void NThreadBase::OnKill()
119 if (iUserContextType != NThread::EContextNone)
121 NThread::TUserContextType t = ((NThread*)this)->UserContextType();
124 case NThread::EContextUserInterrupt:
125 t = NThread::EContextUserInterruptDied;
127 case NThread::EContextSvsrInterrupt1:
128 t = NThread::EContextSvsrInterrupt1Died;
130 case NThread::EContextSvsrInterrupt2:
131 t = NThread::EContextSvsrInterrupt2Died;
133 case NThread::EContextWFAR:
134 t = NThread::EContextWFARDied;
140 iUserContextType = t;
144 /** Called from generic layer when thread exits.
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().
155 void NThreadBase::OnExit()
157 CHECK_PRECONDITIONS(MASK_KERNEL_LOCKED,"NThreadBase::OnExit");
158 if (iUserContextType == NThread::EContextUndefined)
159 iUserContextType = NThread::EContextExec;
162 void NThreadBase::ForceExit()
164 TUint32* sp=(TUint32*)iSavedSP;
165 sp[SP_PC]=(TUint32)__DoForcedExit;
168 void DumpExcInfo(TArmExcInfo& a)
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);
179 void DumpFullRegSet(SFullArmRegSet& a)
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);
202 SAuxiliaryRegs& aux = a.iA;
203 DEBUGPRINT("TEEHBR=%08x CPACR=%08x", aux.iTEEHBR, aux.iCPACR);
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);
213 DEBUGPRINT("FPEXC %08x", a.iMore[0]);
215 DEBUGPRINT("ExcCode %08x", a.iExcCode);
218 #define CONTEXT_ELEMENT_UNDEFINED(val) \
220 TArmContextElement::EUndefined, \
224 #define CONTEXT_ELEMENT_EXCEPTION(reg) \
226 TArmContextElement::EOffsetFromStackTop, \
227 (- (-sizeof(TArmExcInfo)+_FOFF(TArmExcInfo,reg)) )>>2 \
230 #define CONTEXT_ELEMENT_FROM_SP(offset) \
232 TArmContextElement::EOffsetFromSp, \
236 #define CONTEXT_ELEMENT_FROM_STACK_TOP(offset) \
238 TArmContextElement::EOffsetFromStackTop, \
242 #define CONTEXT_ELEMENT_SP_PLUS(offset) \
244 TArmContextElement::ESpPlusOffset, \
248 const TArmContextElement ContextTableException[] =
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),
270 const TArmContextElement ContextTableUndefined[] =
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),
292 // Table used for non dying threads which have been preempted by an interrupt
293 // while in user mode.
295 const TArmContextElement ContextTableUserInterrupt[] =
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),
317 // Table used for threads which have been asynchronously killed after being
318 // preempted by interrupt while in user mode.
320 const TArmContextElement ContextTableUserInterruptDied[] =
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),
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.
346 const TArmContextElement ContextTableSvsrInterrupt1[] =
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),
368 // Table used for threads which have been asynchronously killed while in the situation
369 // described above (see ContextTableSvsrInterrupt1).
371 const TArmContextElement ContextTableSvsrInterrupt1Died[] =
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),
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.
396 const TArmContextElement ContextTableSvsrInterrupt2[] =
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),
418 // Table used for threads which have been asynchronously killed while in the situation
419 // described above (see ContextTableSvsrInterrupt2).
421 const TArmContextElement ContextTableSvsrInterrupt2Died[] =
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),
443 // Table used for non-dying threads blocked on their request semaphore.
445 const TArmContextElement ContextTableWFAR[] =
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),
467 // Table used for threads killed asynchronously while blocked on their request
470 const TArmContextElement ContextTableWFARDied[] =
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),
492 const TArmContextElement ContextTableExec[] =
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),
514 // Table used to retrieve a thread's kernel side context.
515 // Used for kernel threads.
516 const TArmContextElement ContextTableKernel[] =
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),
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.
541 const TArmContextElement ContextTableUserIntrCallback[] =
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),
563 // Table used for non-dying threads which are in a user callback while returning
564 // from being blocked on their request semaphore.
566 const TArmContextElement ContextTableWFARCallback[] =
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),
588 const TArmContextElement* const ThreadUserContextTables[] =
590 ContextTableUndefined, // EContextNone
591 ContextTableException,
592 ContextTableUndefined,
593 ContextTableUserInterrupt,
594 ContextTableUserInterruptDied,
595 ContextTableSvsrInterrupt1,
596 ContextTableSvsrInterrupt1Died,
597 ContextTableSvsrInterrupt2,
598 ContextTableSvsrInterrupt2Died,
600 ContextTableWFARDied,
603 ContextTableUserIntrCallback,
604 ContextTableWFARCallback,
608 /** Return table of pointers to user context tables.
610 Each user context table is an array of TArmContextElement objects, one per
611 ARM CPU register, in the order defined in TArmRegisters.
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.
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.
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.
628 @see TArmContextElement
630 @see TUserContextType
631 @see NKern::SetUserContext
632 @see NKern::GetUserContext
636 EXPORT_C const TArmContextElement* const* NThread::UserContextTables()
638 return &ThreadUserContextTables[0];
642 #ifndef __USER_CONTEXT_TYPE_MACHINE_CODED__
643 extern TBool RescheduledAfterInterrupt(TUint32 /*aAddr*/);
645 /** Get a value which indicates where a thread's user mode context is stored.
647 @return A value that can be used as an index into the tables returned by
648 NThread::UserContextTables().
654 @see UserContextTables
657 EXPORT_C NThread::TUserContextType NThread::UserContextType()
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;
664 // Check for EContextNone and EContextException
665 // Also EContextUserIntrCallback and EContextWFARCallback
666 if(iUserContextType<=EContextException || iUserContextType==EContextUserIntrCallback
667 || iUserContextType==EContextWFARCallback)
668 return (TUserContextType)iUserContextType;
670 // Getting current thread context? must be in exec call as exception
671 // and dying thread cases were tested above.
672 if (this == NCurrentThread())
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))
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))
690 // interrupt before return address, r11 were saved or after registers restored
691 return EContextSvsrInterrupt1;
695 // interrupt after return address, r11 saved
696 return EContextSvsrInterrupt2;
699 // thread was interrupted in supervisor mode
700 // return address and r3-r11 were saved
703 // Transition to supervisor mode must have been due to a SWI
704 if (n==(15+EXTRA_WORDS))
706 // thread must have blocked doing Exec::WaitForAnyRequest
710 // Thread must have been in a SLOW or UNPROTECTED Exec call
714 #endif // __USER_CONTEXT_TYPE_MACHINE_CODED__
716 // Enter and return with kernel locked
717 void NThread::GetContext(TArmRegSet& aContext, TUint32& aAvailRegistersMask, const TArmContextElement* aContextTable)
719 TUint32* sp = (TUint32*)iSavedSP;
720 TUint32* st = (TUint32*)((TUint32)iStackBase+(TUint32)iStackSize);
721 TArmReg* out = (TArmReg*)(&aContext);
722 TBool currentThread = (NCurrentThread() == this);
724 aAvailRegistersMask = 0;
725 if (iNState == EDead)
726 {// This thread's stack may no longer exist so just exit.
730 // Copy available context into provided structure.
731 for (TInt i = 0; i<KArmRegisterCount; ++i)
733 TInt v = aContextTable[i].iValue;
734 TInt t = aContextTable[i].iType;
735 if(!currentThread && t==TArmContextElement::EOffsetFromSp)
737 // thread has been preempted, it is safe to fetch its context
738 // from the info saved in Reschedule().
740 aAvailRegistersMask |= (1<<i);
742 else if(t==TArmContextElement::EOffsetFromStackTop)
745 aAvailRegistersMask |= (1<<i);
747 else if(!currentThread && t==TArmContextElement::ESpPlusOffset)
750 aAvailRegistersMask |= (1<<i);
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)
759 Arm::GetUserSpAndLr(out+EArmSp);
760 aAvailRegistersMask |= (1<<EArmSp) | (1<<EArmLr);
764 // Enter and return with kernel locked
765 void NThread::GetUserContext(TArmRegSet& aContext, TUint32& aAvailRegistersMask)
767 TUserContextType type=UserContextType();
768 NThread::GetContext(aContext, aAvailRegistersMask, UserContextTables()[type]);
771 // Enter and return with kernel locked
772 void NThread::GetSystemContext(TArmRegSet& aContext, TUint32& aAvailRegistersMask)
774 NThread::GetContext(aContext, aAvailRegistersMask, UserContextTables()[EContextKernel]);
777 // Enter and return with kernel locked
778 void NThread::SetUserContext(const TArmRegSet& aContext)
780 if (iNState == EDead)
781 {// This thread's stack may no longer exist so just exit.
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);
791 // Check that target thread is in USR mode, and update only the flags part of the PSR
793 TUint32* tFlagsPtr = &tFlags;
794 TUint32 flagsCtxValue = c[EArmFlags].iValue;
795 switch (c[EArmFlags].iType) // describes how to interpret flagsCtxValue
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
802 case TArmContextElement::EOffsetFromStackTop:
803 // Flags register saved, flagsCtxValue is offset from ToS
804 tFlagsPtr = &st[-flagsCtxValue];
807 case TArmContextElement::EOffsetFromSp:
808 // Flags register saved, flagsCtxValue is offset from SP
810 tFlagsPtr = &sp[flagsCtxValue];
813 // This can only occur when the thread is exiting. Therefore,
814 // we allow it, but the changed values will never be used.
820 // Assertion below will fail with default value ...
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
831 // Copy provided context into stack if possible
832 for (TInt i = 0; i<KArmRegisterCount; ++i)
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)
839 TInt v = c[i].iValue;
841 if(!currentThread && t==TArmContextElement::EOffsetFromSp)
843 // thread has been preempted, it is safe to change context
844 // saved in Reschedule().
847 if(t==TArmContextElement::EOffsetFromStackTop)
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);
857 // Modify a non-running thread's user stack pointer
858 // Enter and return with kernel locked
859 void NThread::ModifyUsp(TLinAddr aUsp)
861 // Check what caused the thread to enter supervisor mode
862 TUint32* sst=(TUint32*)((TUint32)iStackBase+(TUint32)iStackSize);
865 // exception caused transition to supervisor mode
866 TArmExcInfo& e=((TArmExcInfo*)sst)[-1];
870 TUint32* sp=(TUint32*)iSavedSP; // saved supervisor stack pointer
874 /** Get (subset of) user context of specified thread.
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.
881 @param aThread Thread to inspect. It can be the current thread or a
884 @param aContext Pointer to TArmRegSet structure where the context is
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.
892 @see ThreadSetUserContext
894 @pre Call in a thread context.
895 @pre Interrupts must be enabled.
897 EXPORT_C void NKern::ThreadGetUserContext(NThread* aThread, TAny* aContext, TUint32& aAvailRegistersMask)
899 CHECK_PRECONDITIONS(MASK_INTERRUPTS_ENABLED|MASK_NOT_ISR|MASK_NOT_IDFC,"NKern::ThreadGetUserContext");
900 TArmRegSet& a=*(TArmRegSet*)aContext;
901 memclr(aContext, sizeof(TArmRegSet));
903 aThread->GetUserContext(a, aAvailRegistersMask);
907 /** Get (subset of) system context of specified thread.
909 @param aThread Thread to inspect. It can be the current thread or a
912 @param aContext Pointer to TArmRegSet structure where the context is
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.
920 @see ThreadSetUserContext
922 @pre Call in a thread context.
923 @pre Interrupts must be enabled.
925 EXPORT_C void NKern::ThreadGetSystemContext(NThread* aThread, TAny* aContext, TUint32& aAvailRegistersMask)
927 CHECK_PRECONDITIONS(MASK_INTERRUPTS_ENABLED|MASK_NOT_ISR|MASK_NOT_IDFC,"NKern::ThreadGetSystemContext");
928 TArmRegSet& a=*(TArmRegSet*)aContext;
929 memclr(aContext, sizeof(TArmRegSet));
931 aThread->GetSystemContext(a, aAvailRegistersMask);
935 /** Set (subset of) user context of specified thread.
937 @param aThread Thread to modify. It can be the current thread or a
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.
945 @see ThreadGetUserContext
947 @pre Call in a thread context.
948 @pre Interrupts must be enabled.
950 EXPORT_C void NKern::ThreadSetUserContext(NThread* aThread, TAny* aContext)
952 CHECK_PRECONDITIONS(MASK_INTERRUPTS_ENABLED|MASK_NOT_ISR|MASK_NOT_IDFC,"NKern::ThreadSetUserContext");
953 TArmRegSet& a=*(TArmRegSet*)aContext;
955 aThread->SetUserContext(a);
959 /** @internalComponent */
960 void NKern::ThreadModifyUsp(NThread* aThread, TLinAddr aUsp)
963 aThread->ModifyUsp(aUsp);
967 #ifdef __CPU_ARM_USE_DOMAINS
968 TUint32 NThread::Dacr()
970 if (this==TheScheduler.iCurrentThread)
973 TUint32* sp=(TUint32*)iSavedSP; // saved supervisor stack pointer
974 TUint32 dacr=sp[SP_DACR];
979 void NThread::SetDacr(TUint32 aDacr)
981 if (this==TheScheduler.iCurrentThread)
984 TUint32* sp=(TUint32*)iSavedSP; // saved supervisor stack pointer
989 TUint32 NThread::ModifyDacr(TUint32 aClearMask, TUint32 aSetMask)
991 if (this==TheScheduler.iCurrentThread)
992 return Arm::ModifyDacr(aClearMask,aSetMask);
994 TUint32* sp=(TUint32*)iSavedSP; // saved supervisor stack pointer
995 TUint32 dacr=sp[SP_DACR];
996 sp[SP_DACR]=(dacr&~aClearMask)|aSetMask;
1002 #ifdef __CPU_HAS_COPROCESSOR_ACCESS_REG
1003 void NThread::SetCar(TUint32 aCar)
1005 if (this==TheScheduler.iCurrentThread)
1008 TUint32* sp=(TUint32*)iSavedSP; // saved supervisor stack pointer
1016 /** Get the saved coprocessor access register value for a thread
1018 @return The saved value of the CAR, 0 if CPU doesn't have CAR
1019 @pre Don't call from ISR
1024 EXPORT_C TUint32 NThread::Car()
1026 CHECK_PRECONDITIONS(MASK_NOT_ISR,"NThread::Car");
1027 #ifdef __CPU_HAS_COPROCESSOR_ACCESS_REG
1028 if (this==TheScheduler.iCurrentThread)
1031 TUint32* sp=(TUint32*)iSavedSP; // saved supervisor stack pointer
1032 TUint32 car=sp[SP_CAR];
1042 /** Modify the saved coprocessor access register value for a thread
1043 Does nothing if CPU does not have CAR.
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
1053 EXPORT_C TUint32 NThread::ModifyCar(TUint32 aClearMask, TUint32 aSetMask)
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);
1060 TUint32* sp=(TUint32*)iSavedSP; // saved supervisor stack pointer
1061 TUint32 car=sp[SP_CAR];
1062 sp[SP_CAR]=(car&~aClearMask)|aSetMask;
1070 #ifdef __CPU_HAS_VFP
1071 void NThread::SetFpExc(TUint32 aVal)
1073 if (this==TheScheduler.iCurrentThread)
1074 Arm::SetFpExc(aVal);
1076 TUint32* sp=(TUint32*)iSavedSP; // saved supervisor stack pointer
1084 /** Get the saved VFP FPEXC register value for a thread
1086 @return The saved value of FPEXC, 0 if VFP not present
1087 @pre Don't call from ISR
1092 EXPORT_C TUint32 NThread::FpExc()
1094 CHECK_PRECONDITIONS(MASK_NOT_ISR,"NThread::FpExc");
1095 #ifdef __CPU_HAS_VFP
1096 if (this==TheScheduler.iCurrentThread)
1097 return Arm::FpExc();
1099 TUint32* sp=(TUint32*)iSavedSP; // saved supervisor stack pointer
1100 TUint32 r=sp[SP_FPEXC];
1110 /** Modify the saved VFP FPEXC register value for a thread
1111 Does nothing if VFP not present
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
1121 EXPORT_C TUint32 NThread::ModifyFpExc(TUint32 aClearMask, TUint32 aSetMask)
1123 CHECK_PRECONDITIONS(MASK_NOT_ISR,"NThread::ModifyFpExc");
1124 #ifdef __CPU_HAS_VFP
1125 if (this==TheScheduler.iCurrentThread)
1126 return Arm::ModifyFpExc(aClearMask,aSetMask);
1128 TUint32* sp=(TUint32*)iSavedSP; // saved supervisor stack pointer
1129 TUint32 r=sp[SP_FPEXC];
1130 sp[SP_FPEXC]=(r&~aClearMask)|aSetMask;