sl@0: // Copyright (c) 1994-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of the License "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // e32\nkern\arm\ncthrd.cpp sl@0: // sl@0: // sl@0: sl@0: // NThreadBase member data sl@0: #define __INCLUDE_NTHREADBASE_DEFINES__ sl@0: sl@0: #define __INCLUDE_REG_OFFSETS__ sl@0: #include sl@0: sl@0: const TInt KNThreadMinStackSize = 0x100; // needs to be enough for interrupt + reschedule stack sl@0: sl@0: // Called by a thread when it first runs sl@0: extern void __StartThread(); sl@0: sl@0: // Called by a thread which has been forced to exit sl@0: // Interrupts off here, kernel unlocked sl@0: extern void __DoForcedExit(); sl@0: sl@0: void NThreadBase::SetEntry(NThreadFunction aFunc) sl@0: { sl@0: TUint32* sp=(TUint32*)iSavedSP; sl@0: sp[SP_R5]=(TUint32)aFunc; sl@0: } sl@0: sl@0: TInt NThread::Create(SNThreadCreateInfo& aInfo, TBool aInitial) sl@0: { sl@0: // Assert ParameterBlockSize is not negative and is a multiple of 8 bytes sl@0: __NK_ASSERT_ALWAYS((aInfo.iParameterBlockSize&0x80000007)==0); sl@0: sl@0: __NK_ASSERT_ALWAYS(aInfo.iStackBase && aInfo.iStackSize>=aInfo.iParameterBlockSize+KNThreadMinStackSize); sl@0: TInt r=NThreadBase::Create(aInfo,aInitial); sl@0: if (r!=KErrNone) sl@0: return r; sl@0: if (!aInitial) sl@0: { sl@0: TUint32* sp=(TUint32*)(iStackBase+iStackSize-aInfo.iParameterBlockSize); sl@0: TUint32 r6=(TUint32)aInfo.iParameterBlock; sl@0: if (aInfo.iParameterBlockSize) sl@0: { sl@0: wordmove(sp,aInfo.iParameterBlock,aInfo.iParameterBlockSize); sl@0: r6=(TUint32)sp; sl@0: } sl@0: *--sp=(TUint32)__StartThread; // PC sl@0: *--sp=0; // R11 sl@0: *--sp=0; // R10 sl@0: *--sp=0; // R9 sl@0: *--sp=0; // R8 sl@0: *--sp=0; // R7 sl@0: *--sp=r6; // R6 sl@0: *--sp=(TUint32)aInfo.iFunction; // R5 sl@0: *--sp=(TUint32)this; // R4 sl@0: *--sp=0x13; // SPSR_SVC sl@0: *--sp=0; // R14_USR sl@0: *--sp=0; // R13_USR sl@0: #ifdef __CPU_ARM_USE_DOMAINS sl@0: *--sp=Arm::DefaultDomainAccess; // DACR sl@0: #endif sl@0: #ifdef __CPU_HAS_COPROCESSOR_ACCESS_REG sl@0: *--sp=Arm::DefaultCoprocessorAccess; // CAR sl@0: #endif sl@0: #ifdef __CPU_HAS_VFP sl@0: *--sp=VFP_FPEXC_THRD_INIT; // FPEXC sl@0: #endif sl@0: #ifdef __CPU_HAS_CP15_THREAD_ID_REG sl@0: *--sp=0; // TID sl@0: #endif sl@0: #ifdef __CPU_SUPPORT_THUMB2EE sl@0: *--sp=0; // ThumbEE Base sl@0: #endif sl@0: iSavedSP=(TLinAddr)sp; sl@0: } sl@0: else sl@0: { sl@0: #ifdef __CPU_HAS_COPROCESSOR_ACCESS_REG sl@0: #ifdef __CPU_HAS_VFP sl@0: #ifdef __CPU_XSCALE__ sl@0: Arm::ModifyCar(0, 0x0c00); // enable CP10, CP11 sl@0: #else sl@0: Arm::ModifyCar(0, 0x00f00000); // full access to CP10, CP11 sl@0: #endif sl@0: #endif sl@0: Arm::DefaultCoprocessorAccess = Arm::Car(); sl@0: #endif sl@0: NKern::EnableAllInterrupts(); sl@0: } sl@0: #ifdef BTRACE_THREAD_IDENTIFICATION sl@0: BTrace4(BTrace::EThreadIdentification,BTrace::ENanoThreadCreate,this); sl@0: #endif sl@0: return KErrNone; sl@0: } sl@0: sl@0: /** Called from generic layer when thread is killed asynchronously. sl@0: sl@0: For ARM, save reason for last user->kernel switch (if any) so that user sl@0: context can be accessed from EDebugEventRemoveThread hook. Must be done sl@0: before forcing the thread to exit as this alters the saved return address sl@0: which is used to figure out where the context is saved. sl@0: sl@0: @pre kernel locked sl@0: @post kernel locked sl@0: */ sl@0: sl@0: void NThreadBase::OnKill() sl@0: { sl@0: if (iUserContextType != NThread::EContextNone) sl@0: { sl@0: NThread::TUserContextType t = ((NThread*)this)->UserContextType(); sl@0: switch (t) sl@0: { sl@0: case NThread::EContextUserInterrupt: sl@0: t = NThread::EContextUserInterruptDied; sl@0: break; sl@0: case NThread::EContextSvsrInterrupt1: sl@0: t = NThread::EContextSvsrInterrupt1Died; sl@0: break; sl@0: case NThread::EContextSvsrInterrupt2: sl@0: t = NThread::EContextSvsrInterrupt2Died; sl@0: break; sl@0: case NThread::EContextWFAR: sl@0: t = NThread::EContextWFARDied; sl@0: break; sl@0: default: sl@0: // NOP sl@0: break; sl@0: } sl@0: iUserContextType = t; sl@0: } sl@0: } sl@0: sl@0: /** Called from generic layer when thread exits. sl@0: sl@0: For ARM, save that if the thread terminates synchronously the last sl@0: user->kernel switch was an exec call. Do nothing if non-user thread or sl@0: reason already saved in OnKill(). sl@0: sl@0: @pre kernel locked sl@0: @post kernel locked sl@0: @see OnKill sl@0: */ sl@0: sl@0: void NThreadBase::OnExit() sl@0: { sl@0: CHECK_PRECONDITIONS(MASK_KERNEL_LOCKED,"NThreadBase::OnExit"); sl@0: if (iUserContextType == NThread::EContextUndefined) sl@0: iUserContextType = NThread::EContextExec; sl@0: } sl@0: sl@0: void NThreadBase::ForceExit() sl@0: { sl@0: TUint32* sp=(TUint32*)iSavedSP; sl@0: sp[SP_PC]=(TUint32)__DoForcedExit; sl@0: } sl@0: sl@0: void DumpExcInfo(TArmExcInfo& a) sl@0: { sl@0: DEBUGPRINT("Exc %1d Cpsr=%08x FAR=%08x FSR=%08x",a.iExcCode,a.iCpsr,a.iFaultAddress,a.iFaultStatus); sl@0: DEBUGPRINT(" R0=%08x R1=%08x R2=%08x R3=%08x",a.iR0,a.iR1,a.iR2,a.iR3); sl@0: DEBUGPRINT(" R4=%08x R5=%08x R6=%08x R7=%08x",a.iR4,a.iR5,a.iR6,a.iR7); sl@0: DEBUGPRINT(" R8=%08x R9=%08x R10=%08x R11=%08x",a.iR8,a.iR9,a.iR10,a.iR11); sl@0: DEBUGPRINT("R12=%08x R13=%08x R14=%08x R15=%08x",a.iR12,a.iR13,a.iR14,a.iR15); sl@0: DEBUGPRINT("R13Svc=%08x R14Svc=%08x SpsrSvc=%08x",a.iR13Svc,a.iR14Svc,a.iSpsrSvc); sl@0: DEBUGPRINT("Thread %T, KernCSLocked=%d",TheScheduler.iCurrentThread,TheScheduler.iKernCSLocked); sl@0: } sl@0: sl@0: void DumpFullRegSet(SFullArmRegSet& a) sl@0: { sl@0: SNormalRegs& r = a.iN; sl@0: DEBUGPRINT("MODE_USR:"); sl@0: DEBUGPRINT(" R0=%08x R1=%08x R2=%08x R3=%08x", r.iR0, r.iR1, r.iR2, r.iR3); sl@0: DEBUGPRINT(" R4=%08x R5=%08x R6=%08x R7=%08x", r.iR4, r.iR5, r.iR6, r.iR7); sl@0: DEBUGPRINT(" R8=%08x R9=%08x R10=%08x R11=%08x", r.iR8, r.iR9, r.iR10, r.iR11); sl@0: DEBUGPRINT("R12=%08x R13=%08x R14=%08x R15=%08x", r.iR12, r.iR13, r.iR14, r.iR15); sl@0: DEBUGPRINT("CPSR=%08x", r.iFlags); sl@0: DEBUGPRINT("MODE_FIQ:"); sl@0: DEBUGPRINT(" R8=%08x R9=%08x R10=%08x R11=%08x", r.iR8Fiq, r.iR9Fiq, r.iR10Fiq, r.iR11Fiq); sl@0: DEBUGPRINT("R12=%08x R13=%08x R14=%08x SPSR=%08x", r.iR12Fiq, r.iR13Fiq, r.iR14Fiq, r.iSpsrFiq); sl@0: DEBUGPRINT("MODE_IRQ:"); sl@0: DEBUGPRINT("R13=%08x R14=%08x SPSR=%08x", r.iR13Irq, r.iR14Irq, r.iSpsrIrq); sl@0: DEBUGPRINT("MODE_SVC:"); sl@0: DEBUGPRINT("R13=%08x R14=%08x SPSR=%08x", r.iR13Svc, r.iR14Svc, r.iSpsrSvc); sl@0: DEBUGPRINT("MODE_ABT:"); sl@0: DEBUGPRINT("R13=%08x R14=%08x SPSR=%08x", r.iR13Abt, r.iR14Abt, r.iSpsrAbt); sl@0: DEBUGPRINT("MODE_UND:"); sl@0: DEBUGPRINT("R13=%08x R14=%08x SPSR=%08x", r.iR13Und, r.iR14Und, r.iSpsrUnd); sl@0: // DEBUGPRINT("MODE_MON:"); sl@0: // DEBUGPRINT("R13=%08x R14=%08x SPSR=%08x", r.iR13Mon, r.iR14Mon, r.iSpsrMon); sl@0: sl@0: SAuxiliaryRegs& aux = a.iA; sl@0: DEBUGPRINT("TEEHBR=%08x CPACR=%08x", aux.iTEEHBR, aux.iCPACR); sl@0: sl@0: SBankedRegs& b = a.iB[0]; sl@0: DEBUGPRINT(" SCTLR=%08x ACTLR=%08x PRRR=%08x NMRR=%08x", b.iSCTLR, b.iACTLR, b.iPRRR, b.iNMRR); sl@0: DEBUGPRINT(" DACR=%08x TTBR0=%08x TTBR1=%08x TTBCR=%08x", b.iDACR, b.iTTBR0, b.iTTBR1, b.iTTBCR); sl@0: DEBUGPRINT(" VBAR=%08x FCSEID=%08x CTXIDR=%08x", b.iVBAR, b.iFCSEIDR, b.iCTXIDR); sl@0: DEBUGPRINT("Thread ID RWRW=%08x RWRO=%08x RWNO=%08x", b.iRWRWTID, b.iRWROTID, b.iRWNOTID); sl@0: DEBUGPRINT(" DFSR=%08x DFAR=%08x IFSR=%08x IFAR=%08x", b.iDFSR, b.iDFAR, b.iIFSR, b.iIFAR); sl@0: DEBUGPRINT(" ADFSR=%08x AIFSR=%08x", b.iADFSR, b.iAIFSR); sl@0: #ifdef __CPU_HAS_VFP sl@0: DEBUGPRINT("FPEXC %08x", a.iMore[0]); sl@0: #endif sl@0: DEBUGPRINT("ExcCode %08x", a.iExcCode); sl@0: } sl@0: sl@0: #define CONTEXT_ELEMENT_UNDEFINED(val) \ sl@0: { \ sl@0: TArmContextElement::EUndefined, \ sl@0: val \ sl@0: } sl@0: sl@0: #define CONTEXT_ELEMENT_EXCEPTION(reg) \ sl@0: { \ sl@0: TArmContextElement::EOffsetFromStackTop, \ sl@0: (- (-sizeof(TArmExcInfo)+_FOFF(TArmExcInfo,reg)) )>>2 \ sl@0: } sl@0: sl@0: #define CONTEXT_ELEMENT_FROM_SP(offset) \ sl@0: { \ sl@0: TArmContextElement::EOffsetFromSp, \ sl@0: offset \ sl@0: } sl@0: sl@0: #define CONTEXT_ELEMENT_FROM_STACK_TOP(offset) \ sl@0: { \ sl@0: TArmContextElement::EOffsetFromStackTop, \ sl@0: offset \ sl@0: } sl@0: sl@0: #define CONTEXT_ELEMENT_SP_PLUS(offset) \ sl@0: { \ sl@0: TArmContextElement::ESpPlusOffset, \ sl@0: offset \ sl@0: } sl@0: sl@0: const TArmContextElement ContextTableException[] = sl@0: { sl@0: CONTEXT_ELEMENT_EXCEPTION(iR0), sl@0: CONTEXT_ELEMENT_EXCEPTION(iR1), sl@0: CONTEXT_ELEMENT_EXCEPTION(iR2), sl@0: CONTEXT_ELEMENT_EXCEPTION(iR3), sl@0: CONTEXT_ELEMENT_EXCEPTION(iR4), sl@0: CONTEXT_ELEMENT_EXCEPTION(iR5), sl@0: CONTEXT_ELEMENT_EXCEPTION(iR6), sl@0: CONTEXT_ELEMENT_EXCEPTION(iR7), sl@0: CONTEXT_ELEMENT_EXCEPTION(iR8), sl@0: CONTEXT_ELEMENT_EXCEPTION(iR9), sl@0: CONTEXT_ELEMENT_EXCEPTION(iR10), sl@0: CONTEXT_ELEMENT_EXCEPTION(iR11), sl@0: CONTEXT_ELEMENT_EXCEPTION(iR12), sl@0: CONTEXT_ELEMENT_EXCEPTION(iR13), sl@0: CONTEXT_ELEMENT_EXCEPTION(iR14), sl@0: CONTEXT_ELEMENT_EXCEPTION(iR15), sl@0: CONTEXT_ELEMENT_EXCEPTION(iCpsr), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: }; sl@0: sl@0: const TArmContextElement ContextTableUndefined[] = sl@0: { sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(EUserMode), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: }; sl@0: sl@0: // Table used for non dying threads which have been preempted by an interrupt sl@0: // while in user mode. sl@0: sl@0: const TArmContextElement ContextTableUserInterrupt[] = sl@0: { sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(6), sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(5), sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(4), sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(3), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R4), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R5), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R6), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R7), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R8), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R9), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R10), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R11), sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(2), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R13U), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R14U), sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(1), sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(8), // interrupted CPSR sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: }; sl@0: sl@0: // Table used for threads which have been asynchronously killed after being sl@0: // preempted by interrupt while in user mode. sl@0: sl@0: const TArmContextElement ContextTableUserInterruptDied[] = sl@0: { sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(6), sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(5), sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(4), sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(3), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(2), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R13U), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R14U), sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(1), sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(8), // interrupted CPSR sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: }; sl@0: sl@0: // Table used for threads which have been preempted by an interrupt while in sl@0: // supervisor mode in the SWI handler either before the return address was sl@0: // saved or after the registers were restored. sl@0: sl@0: const TArmContextElement ContextTableSvsrInterrupt1[] = sl@0: { sl@0: CONTEXT_ELEMENT_FROM_SP(SP_NEXT+USER_MEMORY_GUARD_SAVE_WORDS+2), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_NEXT+USER_MEMORY_GUARD_SAVE_WORDS+3), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_NEXT+USER_MEMORY_GUARD_SAVE_WORDS+4), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_NEXT+USER_MEMORY_GUARD_SAVE_WORDS+5), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R4), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R5), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R6), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R7), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R8), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R9), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R10), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R11), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_NEXT+USER_MEMORY_GUARD_SAVE_WORDS+6), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R13U), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R14U), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_NEXT+USER_MEMORY_GUARD_SAVE_WORDS+6), // r15 = r12 sl@0: CONTEXT_ELEMENT_UNDEFINED(EUserMode), // can't get flags so just use 'user mode' sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: }; sl@0: sl@0: // Table used for threads which have been asynchronously killed while in the situation sl@0: // described above (see ContextTableSvsrInterrupt1). sl@0: sl@0: const TArmContextElement ContextTableSvsrInterrupt1Died[] = sl@0: { sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R13U), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R14U), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(EUserMode), // can't get flags so just use 'user mode' sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: }; sl@0: sl@0: // Table used for threads which have been preempted by an interrupt while in sl@0: // supervisor mode in the SWI handler after the return address was saved. sl@0: sl@0: const TArmContextElement ContextTableSvsrInterrupt2[] = sl@0: { sl@0: CONTEXT_ELEMENT_FROM_SP(SP_NEXT+USER_MEMORY_GUARD_SAVE_WORDS+2), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_NEXT+USER_MEMORY_GUARD_SAVE_WORDS+3), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_NEXT+USER_MEMORY_GUARD_SAVE_WORDS+4), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_NEXT+USER_MEMORY_GUARD_SAVE_WORDS+5), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R4), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R5), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R6), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R7), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R8), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R9), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R10), sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(2), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_NEXT+USER_MEMORY_GUARD_SAVE_WORDS+6), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R13U), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R14U), sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(1), sl@0: CONTEXT_ELEMENT_UNDEFINED(EUserMode), // can't get flags so just use 'user mode' sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: }; sl@0: sl@0: // Table used for threads which have been asynchronously killed while in the situation sl@0: // described above (see ContextTableSvsrInterrupt2). sl@0: sl@0: const TArmContextElement ContextTableSvsrInterrupt2Died[] = sl@0: { sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R13U), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R14U), sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(1), sl@0: CONTEXT_ELEMENT_UNDEFINED(EUserMode), // can't get flags so just use 'user mode' sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: }; sl@0: sl@0: // Table used for non-dying threads blocked on their request semaphore. sl@0: sl@0: const TArmContextElement ContextTableWFAR[] = sl@0: { sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R4), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R5), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R6), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R7), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R8), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R9), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R10), sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(2), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R13U), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R14U), sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(1), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_SPSR), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: }; sl@0: sl@0: // Table used for threads killed asynchronously while blocked on their request sl@0: // semaphore. sl@0: sl@0: const TArmContextElement ContextTableWFARDied[] = sl@0: { sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R13U), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R14U), sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(1), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_SPSR), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: }; sl@0: sl@0: const TArmContextElement ContextTableExec[] = sl@0: { sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(10), sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(9), sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(8), sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(7), sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(6), sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(5), sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(4), sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(3), sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(2), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R13U), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R14U), sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(1), sl@0: CONTEXT_ELEMENT_UNDEFINED(EUserMode), // can't get flags so just use 'user mode' sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: }; sl@0: sl@0: // Table used to retrieve a thread's kernel side context. sl@0: // Used for kernel threads. sl@0: const TArmContextElement ContextTableKernel[] = sl@0: { sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R4), // r4 before reschedule sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R5), // r5 before reschedule sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R6), // r6 before reschedule sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R7), // r7 before reschedule sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R8), // r8 before reschedule sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R9), // r9 before reschedule sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R10), // r10 before reschedule sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R11), // r11 before reschedule sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_SP_PLUS(SP_NEXT), // supervisor stack pointer before reschedule sl@0: CONTEXT_ELEMENT_UNDEFINED(0), // supervisor lr is unknown sl@0: CONTEXT_ELEMENT_FROM_SP(SP_PC), // return address from reschedule sl@0: CONTEXT_ELEMENT_UNDEFINED(ESvcMode), // can't get flags so just use 'supervisor mode' sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: }; sl@0: sl@0: // Table used for non dying threads which are in a user callback while returning sl@0: // from having been preempted by an interrupt while in user mode. sl@0: sl@0: const TArmContextElement ContextTableUserIntrCallback[] = sl@0: { sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(6), sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(5), sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(4), sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(3), sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(8+USER_MEMORY_GUARD_SAVE_WORDS+9), sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(8+USER_MEMORY_GUARD_SAVE_WORDS+8), sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(8+USER_MEMORY_GUARD_SAVE_WORDS+7), sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(8+USER_MEMORY_GUARD_SAVE_WORDS+6), sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(8+USER_MEMORY_GUARD_SAVE_WORDS+5), sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(8+USER_MEMORY_GUARD_SAVE_WORDS+4), sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(8+USER_MEMORY_GUARD_SAVE_WORDS+3), sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(8+USER_MEMORY_GUARD_SAVE_WORDS+2), sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(2), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R13U), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R14U), sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(1), sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(8), // interrupted CPSR sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: }; sl@0: sl@0: // Table used for non-dying threads which are in a user callback while returning sl@0: // from being blocked on their request semaphore. sl@0: sl@0: const TArmContextElement ContextTableWFARCallback[] = sl@0: { sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(11), sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(10), sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(9), sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(8), sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(7), sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(6), sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(5), sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(2), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R13U), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_R14U), sl@0: CONTEXT_ELEMENT_FROM_STACK_TOP(1), sl@0: CONTEXT_ELEMENT_FROM_SP(SP_SPSR), sl@0: CONTEXT_ELEMENT_UNDEFINED(0), sl@0: }; sl@0: sl@0: const TArmContextElement* const ThreadUserContextTables[] = sl@0: { sl@0: ContextTableUndefined, // EContextNone sl@0: ContextTableException, sl@0: ContextTableUndefined, sl@0: ContextTableUserInterrupt, sl@0: ContextTableUserInterruptDied, sl@0: ContextTableSvsrInterrupt1, sl@0: ContextTableSvsrInterrupt1Died, sl@0: ContextTableSvsrInterrupt2, sl@0: ContextTableSvsrInterrupt2Died, sl@0: ContextTableWFAR, sl@0: ContextTableWFARDied, sl@0: ContextTableExec, sl@0: ContextTableKernel, sl@0: ContextTableUserIntrCallback, sl@0: ContextTableWFARCallback, sl@0: 0 // Null terminated sl@0: }; sl@0: sl@0: /** Return table of pointers to user context tables. sl@0: sl@0: Each user context table is an array of TArmContextElement objects, one per sl@0: ARM CPU register, in the order defined in TArmRegisters. sl@0: sl@0: The master table contains pointers to the user context tables in the order sl@0: defined in TUserContextType. There are as many user context tables as sl@0: scenarii leading a user thread to switch to privileged mode. sl@0: sl@0: Stop-mode debug agents should use this function to store the address of the sl@0: master table at a location known to the host debugger. Run-mode debug sl@0: agents are advised to use NKern::GetUserContext() and sl@0: NKern::SetUserContext() instead. sl@0: sl@0: @return A pointer to the master table. The master table is NULL sl@0: terminated. The master and user context tables are guaranteed to remain at sl@0: the same location for the lifetime of the OS execution so it is safe the sl@0: cache the returned address. sl@0: sl@0: @see UserContextType sl@0: @see TArmContextElement sl@0: @see TArmRegisters sl@0: @see TUserContextType sl@0: @see NKern::SetUserContext sl@0: @see NKern::GetUserContext sl@0: sl@0: @publishedPartner sl@0: */ sl@0: EXPORT_C const TArmContextElement* const* NThread::UserContextTables() sl@0: { sl@0: return &ThreadUserContextTables[0]; sl@0: } sl@0: sl@0: sl@0: #ifndef __USER_CONTEXT_TYPE_MACHINE_CODED__ sl@0: extern TBool RescheduledAfterInterrupt(TUint32 /*aAddr*/); sl@0: sl@0: /** Get a value which indicates where a thread's user mode context is stored. sl@0: sl@0: @return A value that can be used as an index into the tables returned by sl@0: NThread::UserContextTables(). sl@0: sl@0: @pre any context sl@0: @pre kernel locked sl@0: @post kernel locked sl@0: sl@0: @see UserContextTables sl@0: @publishedPartner sl@0: */ sl@0: EXPORT_C NThread::TUserContextType NThread::UserContextType() sl@0: { sl@0: CHECK_PRECONDITIONS(MASK_KERNEL_LOCKED,"NThread::UserContextType"); sl@0: // Dying thread? use context saved earlier by kernel sl@0: if (iCsFunction == ECSExitInProgress) sl@0: return (TUserContextType)iUserContextType; sl@0: sl@0: // Check for EContextNone and EContextException sl@0: // Also EContextUserIntrCallback and EContextWFARCallback sl@0: if(iUserContextType<=EContextException || iUserContextType==EContextUserIntrCallback sl@0: || iUserContextType==EContextWFARCallback) sl@0: return (TUserContextType)iUserContextType; sl@0: sl@0: // Getting current thread context? must be in exec call as exception sl@0: // and dying thread cases were tested above. sl@0: if (this == NCurrentThread()) sl@0: return EContextExec; sl@0: sl@0: // Check what caused the thread to enter supervisor mode sl@0: TUint32* sst=(TUint32*)((TUint32)iStackBase+(TUint32)iStackSize); sl@0: TUint32* sp=(TUint32*)iSavedSP; // saved supervisor stack pointer sl@0: TInt n=sst-sp; // number of words on the supervisor stack sl@0: TUint32 resched_ret=sp[SP_PC]; // return address from reschedule sl@0: if (RescheduledAfterInterrupt(resched_ret)) sl@0: { sl@0: // thread was preempted due to an interrupt sl@0: // interrupt and reschedule will have pushed 20+EXTRA words onto the stack sl@0: if ((sp[SP_NEXT]&EMaskMode)==EUserMode) // interrupted mode = user? sl@0: return NThread::EContextUserInterrupt; sl@0: if (n<(30+EXTRA_WORDS)) // n<30 if interrupt occurred in exec call entry before r3-r10 saved sl@0: { // or after r3-r10 restored sl@0: if (n==(20+EXTRA_WORDS)) sl@0: { sl@0: // interrupt before return address, r11 were saved or after registers restored sl@0: return EContextSvsrInterrupt1; sl@0: } sl@0: else sl@0: { sl@0: // interrupt after return address, r11 saved sl@0: return EContextSvsrInterrupt2; sl@0: } sl@0: } sl@0: // thread was interrupted in supervisor mode sl@0: // return address and r3-r11 were saved sl@0: } sl@0: sl@0: // Transition to supervisor mode must have been due to a SWI sl@0: if (n==(15+EXTRA_WORDS)) sl@0: { sl@0: // thread must have blocked doing Exec::WaitForAnyRequest sl@0: return EContextWFAR; sl@0: } sl@0: sl@0: // Thread must have been in a SLOW or UNPROTECTED Exec call sl@0: return EContextExec; sl@0: } sl@0: sl@0: #endif // __USER_CONTEXT_TYPE_MACHINE_CODED__ sl@0: sl@0: // Enter and return with kernel locked sl@0: void NThread::GetContext(TArmRegSet& aContext, TUint32& aAvailRegistersMask, const TArmContextElement* aContextTable) sl@0: { sl@0: TUint32* sp = (TUint32*)iSavedSP; sl@0: TUint32* st = (TUint32*)((TUint32)iStackBase+(TUint32)iStackSize); sl@0: TArmReg* out = (TArmReg*)(&aContext); sl@0: TBool currentThread = (NCurrentThread() == this); sl@0: sl@0: aAvailRegistersMask = 0; sl@0: if (iNState == EDead) sl@0: {// This thread's stack may no longer exist so just exit. sl@0: return; sl@0: } sl@0: sl@0: // Copy available context into provided structure. sl@0: for (TInt i = 0; iGetUserContext(a, aAvailRegistersMask); sl@0: NKern::Unlock(); sl@0: } sl@0: sl@0: /** Get (subset of) system context of specified thread. sl@0: sl@0: @param aThread Thread to inspect. It can be the current thread or a sl@0: non-current one. sl@0: sl@0: @param aContext Pointer to TArmRegSet structure where the context is sl@0: copied. sl@0: sl@0: @param aAvailRegistersMask Bit mask telling which subset of the context is sl@0: available and has been copied to aContext (1: register available / 0: not sl@0: available). Bit 0 stands for register R0. sl@0: sl@0: @see TArmRegSet sl@0: @see ThreadSetUserContext sl@0: sl@0: @pre Call in a thread context. sl@0: @pre Interrupts must be enabled. sl@0: */ sl@0: EXPORT_C void NKern::ThreadGetSystemContext(NThread* aThread, TAny* aContext, TUint32& aAvailRegistersMask) sl@0: { sl@0: CHECK_PRECONDITIONS(MASK_INTERRUPTS_ENABLED|MASK_NOT_ISR|MASK_NOT_IDFC,"NKern::ThreadGetSystemContext"); sl@0: TArmRegSet& a=*(TArmRegSet*)aContext; sl@0: memclr(aContext, sizeof(TArmRegSet)); sl@0: NKern::Lock(); sl@0: aThread->GetSystemContext(a, aAvailRegistersMask); sl@0: NKern::Unlock(); sl@0: } sl@0: sl@0: /** Set (subset of) user context of specified thread. sl@0: sl@0: @param aThread Thread to modify. It can be the current thread or a sl@0: non-current one. sl@0: sl@0: @param aContext Pointer to TArmRegSet structure containing the context sl@0: to set. The values of registers which aren't part of the context saved sl@0: on the supervisor stack are ignored. sl@0: sl@0: @see TArmRegSet sl@0: @see ThreadGetUserContext sl@0: sl@0: @pre Call in a thread context. sl@0: @pre Interrupts must be enabled. sl@0: */ sl@0: EXPORT_C void NKern::ThreadSetUserContext(NThread* aThread, TAny* aContext) sl@0: { sl@0: CHECK_PRECONDITIONS(MASK_INTERRUPTS_ENABLED|MASK_NOT_ISR|MASK_NOT_IDFC,"NKern::ThreadSetUserContext"); sl@0: TArmRegSet& a=*(TArmRegSet*)aContext; sl@0: NKern::Lock(); sl@0: aThread->SetUserContext(a); sl@0: NKern::Unlock(); sl@0: } sl@0: sl@0: /** @internalComponent */ sl@0: void NKern::ThreadModifyUsp(NThread* aThread, TLinAddr aUsp) sl@0: { sl@0: NKern::Lock(); sl@0: aThread->ModifyUsp(aUsp); sl@0: NKern::Unlock(); sl@0: } sl@0: sl@0: #ifdef __CPU_ARM_USE_DOMAINS sl@0: TUint32 NThread::Dacr() sl@0: { sl@0: if (this==TheScheduler.iCurrentThread) sl@0: return Arm::Dacr(); sl@0: NKern::Lock(); sl@0: TUint32* sp=(TUint32*)iSavedSP; // saved supervisor stack pointer sl@0: TUint32 dacr=sp[SP_DACR]; sl@0: NKern::Unlock(); sl@0: return dacr; sl@0: } sl@0: sl@0: void NThread::SetDacr(TUint32 aDacr) sl@0: { sl@0: if (this==TheScheduler.iCurrentThread) sl@0: Arm::SetDacr(aDacr); sl@0: NKern::Lock(); sl@0: TUint32* sp=(TUint32*)iSavedSP; // saved supervisor stack pointer sl@0: sp[SP_DACR]=aDacr; sl@0: NKern::Unlock(); sl@0: } sl@0: sl@0: TUint32 NThread::ModifyDacr(TUint32 aClearMask, TUint32 aSetMask) sl@0: { sl@0: if (this==TheScheduler.iCurrentThread) sl@0: return Arm::ModifyDacr(aClearMask,aSetMask); sl@0: NKern::Lock(); sl@0: TUint32* sp=(TUint32*)iSavedSP; // saved supervisor stack pointer sl@0: TUint32 dacr=sp[SP_DACR]; sl@0: sp[SP_DACR]=(dacr&~aClearMask)|aSetMask; sl@0: NKern::Unlock(); sl@0: return dacr; sl@0: } sl@0: #endif sl@0: sl@0: #ifdef __CPU_HAS_COPROCESSOR_ACCESS_REG sl@0: void NThread::SetCar(TUint32 aCar) sl@0: { sl@0: if (this==TheScheduler.iCurrentThread) sl@0: Arm::SetCar(aCar); sl@0: NKern::Lock(); sl@0: TUint32* sp=(TUint32*)iSavedSP; // saved supervisor stack pointer sl@0: sp[SP_CAR]=aCar; sl@0: NKern::Unlock(); sl@0: } sl@0: #endif sl@0: sl@0: sl@0: sl@0: /** Get the saved coprocessor access register value for a thread sl@0: sl@0: @return The saved value of the CAR, 0 if CPU doesn't have CAR sl@0: @pre Don't call from ISR sl@0: sl@0: @publishedPartner sl@0: @released sl@0: */ sl@0: EXPORT_C TUint32 NThread::Car() sl@0: { sl@0: CHECK_PRECONDITIONS(MASK_NOT_ISR,"NThread::Car"); sl@0: #ifdef __CPU_HAS_COPROCESSOR_ACCESS_REG sl@0: if (this==TheScheduler.iCurrentThread) sl@0: return Arm::Car(); sl@0: NKern::Lock(); sl@0: TUint32* sp=(TUint32*)iSavedSP; // saved supervisor stack pointer sl@0: TUint32 car=sp[SP_CAR]; sl@0: NKern::Unlock(); sl@0: return car; sl@0: #else sl@0: return 0; sl@0: #endif sl@0: } sl@0: sl@0: sl@0: sl@0: /** Modify the saved coprocessor access register value for a thread sl@0: Does nothing if CPU does not have CAR. sl@0: sl@0: @param aClearMask Mask of bits to clear (1 = clear this bit) sl@0: @param aSetMask Mask of bits to set (1 = set this bit) sl@0: @return The original saved value of the CAR, 0 if CPU doesn't have CAR sl@0: @pre Don't call from ISR sl@0: sl@0: @publishedPartner sl@0: @released sl@0: */ sl@0: EXPORT_C TUint32 NThread::ModifyCar(TUint32 aClearMask, TUint32 aSetMask) sl@0: { sl@0: CHECK_PRECONDITIONS(MASK_NOT_ISR,"NThread::ModifyCar"); sl@0: #ifdef __CPU_HAS_COPROCESSOR_ACCESS_REG sl@0: if (this==TheScheduler.iCurrentThread) sl@0: return Arm::ModifyCar(aClearMask,aSetMask); sl@0: NKern::Lock(); sl@0: TUint32* sp=(TUint32*)iSavedSP; // saved supervisor stack pointer sl@0: TUint32 car=sp[SP_CAR]; sl@0: sp[SP_CAR]=(car&~aClearMask)|aSetMask; sl@0: NKern::Unlock(); sl@0: return car; sl@0: #else sl@0: return 0; sl@0: #endif sl@0: } sl@0: sl@0: #ifdef __CPU_HAS_VFP sl@0: void NThread::SetFpExc(TUint32 aVal) sl@0: { sl@0: if (this==TheScheduler.iCurrentThread) sl@0: Arm::SetFpExc(aVal); sl@0: NKern::Lock(); sl@0: TUint32* sp=(TUint32*)iSavedSP; // saved supervisor stack pointer sl@0: sp[SP_FPEXC]=aVal; sl@0: NKern::Unlock(); sl@0: } sl@0: #endif sl@0: sl@0: sl@0: sl@0: /** Get the saved VFP FPEXC register value for a thread sl@0: sl@0: @return The saved value of FPEXC, 0 if VFP not present sl@0: @pre Don't call from ISR sl@0: sl@0: @publishedPartner sl@0: @released sl@0: */ sl@0: EXPORT_C TUint32 NThread::FpExc() sl@0: { sl@0: CHECK_PRECONDITIONS(MASK_NOT_ISR,"NThread::FpExc"); sl@0: #ifdef __CPU_HAS_VFP sl@0: if (this==TheScheduler.iCurrentThread) sl@0: return Arm::FpExc(); sl@0: NKern::Lock(); sl@0: TUint32* sp=(TUint32*)iSavedSP; // saved supervisor stack pointer sl@0: TUint32 r=sp[SP_FPEXC]; sl@0: NKern::Unlock(); sl@0: return r; sl@0: #else sl@0: return 0; sl@0: #endif sl@0: } sl@0: sl@0: sl@0: sl@0: /** Modify the saved VFP FPEXC register value for a thread sl@0: Does nothing if VFP not present sl@0: sl@0: @param aClearMask Mask of bits to clear (1 = clear this bit) sl@0: @param aSetMask Mask of bits to set (1 = set this bit) sl@0: @return The original saved value of FPEXC, 0 if VFP not present sl@0: @pre Don't call from ISR sl@0: sl@0: @publishedPartner sl@0: @released sl@0: */ sl@0: EXPORT_C TUint32 NThread::ModifyFpExc(TUint32 aClearMask, TUint32 aSetMask) sl@0: { sl@0: CHECK_PRECONDITIONS(MASK_NOT_ISR,"NThread::ModifyFpExc"); sl@0: #ifdef __CPU_HAS_VFP sl@0: if (this==TheScheduler.iCurrentThread) sl@0: return Arm::ModifyFpExc(aClearMask,aSetMask); sl@0: NKern::Lock(); sl@0: TUint32* sp=(TUint32*)iSavedSP; // saved supervisor stack pointer sl@0: TUint32 r=sp[SP_FPEXC]; sl@0: sp[SP_FPEXC]=(r&~aClearMask)|aSetMask; sl@0: NKern::Unlock(); sl@0: return r; sl@0: #else sl@0: return 0; sl@0: #endif sl@0: } sl@0: