sl@0: // Copyright (c) 2007-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\include\nkernsmp\arm\nk_plat.h sl@0: // sl@0: // WARNING: This file contains some APIs which are internal and are subject sl@0: // to change without notice. Such APIs should therefore not be used sl@0: // outside the Kernel and Hardware Services package. sl@0: // sl@0: sl@0: /** sl@0: @file sl@0: @internalComponent sl@0: */ sl@0: sl@0: #ifndef __NK_ARM_H__ sl@0: #define __NK_ARM_H__ sl@0: #include sl@0: sl@0: // These macros are intended for Symbian use only. sl@0: // It may not be possible to build the kernel if any of these macros are undefined sl@0: //#define __SCHEDULER_MACHINE_CODED__ sl@0: //#define __DFC_MACHINE_CODED__ sl@0: //#define __MSTIM_MACHINE_CODED__ sl@0: #define __PRI_LIST_MACHINE_CODED__ sl@0: #define __FAST_SEM_MACHINE_CODED__ sl@0: #define __FAST_MUTEX_MACHINE_CODED__ sl@0: #define __NTHREAD_WAITSTATE_MACHINE_CODED__ sl@0: sl@0: // TSubScheduler member data sl@0: #define i_ScuAddr iExtras[4] // Address of SCU (also in TScheduler) sl@0: #define i_GicDistAddr iExtras[5] // Address of GIC Distributor (also in TScheduler) sl@0: #define i_GicCpuIfcAddr iExtras[6] // Address of GIC CPU Interface (also in TScheduler) sl@0: #define i_LocalTimerAddr iExtras[7] // Address of local timer registers (also in TScheduler) sl@0: #define i_IrqCount iExtras[8] // count of interrupts handled sl@0: #define i_IrqNestCount iExtras[9] // IRQ nest count for this CPU (starts at -1) sl@0: #define i_ExcInfo iExtras[10] // pointer to exception info for crash debugger sl@0: #define i_CrashState iExtras[11] // 0=normal, 1=this CPU faulted, 2=this CPU has received an NMI and halted sl@0: #define i_AbtStackTop iExtras[12] // Top of ABT stack for this CPU, also used to point to SFullArmRegSet sl@0: #define i_UndStackTop iExtras[13] // Top of UND stack for this CPU sl@0: #define i_FiqStackTop iExtras[14] // Top of FIQ stack for this CPU sl@0: #define i_IrqStackTop iExtras[15] // Top of IRQ stack for this CPU sl@0: #define i_TimerMultF iExtras[16] // Timer frequency / Max Timer frequency * 2^32 sl@0: #define i_TimerMultI iExtras[17] // Max Timer frequency / Timer frequency * 2^24 sl@0: #define i_CpuMult iExtras[18] // CPU frequency / Max CPU frequency * 2^32 sl@0: #define i_LastTimerSet iExtras[20] // Value last written to local timer counter sl@0: #define i_TimestampError iExtras[21] // Current error in the timestamp sl@0: #define i_MaxCorrection iExtras[22] // Maximum correction to timestamp in one go sl@0: #define i_TimerGap iExtras[23] // Timestamp ticks taken to read and write local timer counter sl@0: sl@0: #define i_Regs iExtras[12] // Alias for i_AbtStackTop sl@0: sl@0: // TScheduler member data sl@0: #define i_TimerMax iExtras[16] // Maximum per-CPU timer frequency (after prescaling) sl@0: sl@0: sl@0: #define RESCHED_IPI_VECTOR 0x00 sl@0: #define GENERIC_IPI_VECTOR 0x01 sl@0: #define TRANSFERRED_IRQ_VECTOR 0x02 sl@0: #define CRASH_IPI_VECTOR 0x03 // would really like this to be a FIQ sl@0: #define BOOT_IPI_VECTOR 0x04 // used during boot to handshake with APs sl@0: #define RESERVED_IPI_VECTOR_1 0x05 // reserved for future kernel functionality sl@0: #define RESERVED_IPI_VECTOR_2 0x06 // reserved for future kernel functionality sl@0: #define RESERVED_IPI_VECTOR_3 0x07 // reserved for future kernel functionality sl@0: sl@0: #if defined(__CPU_ARM11MP__) sl@0: #define TIMESLICE_VECTOR 0x1D // vector 29 is per-CPU timer interrupt sl@0: // vector 30 is per-CPU Watchdog timer when not in watchdog mode sl@0: // vector 31 is external nIRQ local interrupt pin sl@0: #elif defined(__CPU_CORTEX_A9__) sl@0: #define TIMESLICE_VECTOR 0x1D // vector 29 is per-CPU timer interrupt sl@0: // vector 30 is per-CPU Watchdog timer when not in watchdog mode sl@0: #else sl@0: #error TIMESLICE_VECTOR not defined sl@0: #endif sl@0: sl@0: sl@0: //extern "C" TSubScheduler* SubSchedulerLookupTable[256]; // look up subscheduler from APIC ID sl@0: sl@0: const TUint32 KNThreadContextFlagThumbBit0=1; sl@0: sl@0: /** Registers saved by the scheduler sl@0: sl@0: Let's just have the same stack layout for all CPUs shall we? sl@0: TEEHBR, FpExc may not be used but leave space on the stack for them. sl@0: sl@0: @internalComponent sl@0: */ sl@0: struct SThreadReschedStack sl@0: { sl@0: TUint32 iFpExc; // VFP enable sl@0: TUint32 iCar; // coprocessor access register sl@0: TUint32 iTEEHBR; // Thumb2-EE Handler Base sl@0: TUint32 iRWROTID; // User RO Thread ID sl@0: TUint32 iRWRWTID; // User RW Thread ID sl@0: TUint32 iDacr; // domain access control sl@0: TUint32 iSpare; sl@0: TUint32 iSpsrSvc; sl@0: TUint32 iSPRschdFlg; // Stack pointer plus flag indicating reschedule occurred sl@0: TUint32 iR15; // return address from Reschedule() sl@0: }; sl@0: sl@0: /** Registers saved on any exception, interrupt or system call sl@0: sl@0: @internalComponent sl@0: */ sl@0: struct SThreadExcStack sl@0: { sl@0: enum TType sl@0: { sl@0: EPrefetch =0, // prefetch abort sl@0: EData =1, // data abort sl@0: EUndef =2, // undefined instruction sl@0: EIrq =3, // IRQ interrupt sl@0: EFiq =4, // FIQ interrupt sl@0: ESvc =5, // SWI sl@0: EInit =6, // Thread has never run sl@0: EStub =7, // Stub indicating parameter block still on stack sl@0: }; sl@0: sl@0: TUint32 iR0; sl@0: TUint32 iR1; sl@0: TUint32 iR2; sl@0: TUint32 iR3; sl@0: TUint32 iR4; sl@0: TUint32 iR5; sl@0: TUint32 iR6; sl@0: TUint32 iR7; sl@0: TUint32 iR8; sl@0: TUint32 iR9; sl@0: TUint32 iR10; sl@0: TUint32 iR11; sl@0: TUint32 iR12; sl@0: TUint32 iR13usr; // always user mode R13 sl@0: TUint32 iR14usr; // always user mode R14 sl@0: TUint32 iExcCode; sl@0: TUint32 iR15; // return address sl@0: TUint32 iCPSR; // return CPSR sl@0: }; sl@0: sl@0: /** sl@0: @internalComponent sl@0: */ sl@0: struct SThreadStackStub sl@0: { sl@0: TLinAddr iPBlock; // pointer to parameter block sl@0: TUint32 iExcCode; // always EStub sl@0: TUint32 iR15; // unused sl@0: TUint32 iCPSR; // unused sl@0: }; sl@0: sl@0: /** sl@0: @internalComponent sl@0: */ sl@0: struct SThreadInitStack sl@0: { sl@0: SThreadReschedStack iR; sl@0: SThreadExcStack iX; sl@0: }; sl@0: sl@0: sl@0: /** sl@0: @internalComponent sl@0: */ sl@0: struct SThreadIrqStack sl@0: { sl@0: SThreadReschedStack iR; sl@0: TUint32 iUMGSave; // User memory guard state (if active) sl@0: TUint32 iR14svc; sl@0: SThreadExcStack iX; sl@0: }; sl@0: sl@0: sl@0: class TArmContextElement; sl@0: class TArmRegSet; sl@0: sl@0: /** ARM-specific part of the nano-thread abstraction. sl@0: @internalComponent sl@0: */ sl@0: class NThread : public NThreadBase sl@0: { sl@0: public: sl@0: TInt Create(SNThreadCreateInfo& aInfo, TBool aInitial); sl@0: inline void Stillborn() sl@0: {} sl@0: sl@0: /** Value indicating what event caused thread to enter privileged mode. sl@0: @publishedPartner sl@0: @released sl@0: */ sl@0: enum TUserContextType sl@0: { sl@0: EContextNone=0, /**< Thread has no user context */ sl@0: EContextException=1, /**< Hardware exception while in user mode */ sl@0: EContextUndefined, sl@0: EContextUserInterrupt, /**< Preempted by interrupt taken in user mode */ sl@0: EContextUserInterruptDied, /**< Killed while preempted by interrupt taken in user mode */ // NOT USED sl@0: EContextSvsrInterrupt1, /**< Preempted by interrupt taken in executive call handler */ sl@0: EContextSvsrInterrupt1Died, /**< Killed while preempted by interrupt taken in executive call handler */ // NOT USED sl@0: EContextSvsrInterrupt2, /**< Preempted by interrupt taken in executive call handler */ // NOT USED sl@0: EContextSvsrInterrupt2Died, /**< Killed while preempted by interrupt taken in executive call handler */ // NOT USED sl@0: EContextWFAR, /**< Blocked on User::WaitForAnyRequest() */ sl@0: EContextWFARDied, /**< Killed while blocked on User::WaitForAnyRequest() */ // NOT USED sl@0: EContextExec, /**< Slow executive call */ sl@0: EContextKernel, /**< Kernel side context (for kernel threads) */ sl@0: EContextKernel1, /**< Kernel side context (for kernel threads) (NKern::Unlock, NKern::PreemptionPoint) */ sl@0: EContextKernel2, /**< Kernel side context (for kernel threads) (NKern::FSWait, NKern::WaitForAnyRequest) */ sl@0: EContextKernel3, /**< Kernel side context (for kernel threads) (Interrupt) */ sl@0: EContextKernel4, /**< Kernel side context (for kernel threads) (Exec::WaitForAnyRequest) */ sl@0: }; sl@0: sl@0: IMPORT_C static const TArmContextElement* const* UserContextTables(); sl@0: IMPORT_C TUserContextType UserContextType(); sl@0: void GetUserContext(TArmRegSet& aContext, TUint32& aAvailRegistersMask); sl@0: void SetUserContext(const TArmRegSet& aContext, TUint32& aRegMask); sl@0: void GetSystemContext(TArmRegSet& aContext, TUint32& aAvailRegistersMask); sl@0: sl@0: TUint32 Dacr(); sl@0: void SetDacr(TUint32 aDacr); sl@0: TUint32 ModifyDacr(TUint32 aClearMask, TUint32 aSetMask); sl@0: sl@0: void SetCar(TUint32 aDacr); sl@0: IMPORT_C TUint32 Car(); sl@0: IMPORT_C TUint32 ModifyCar(TUint32 aClearMask, TUint32 aSetMask); sl@0: sl@0: #ifdef __CPU_HAS_VFP sl@0: void SetFpExc(TUint32 aDacr); sl@0: #endif sl@0: IMPORT_C TUint32 FpExc(); sl@0: IMPORT_C TUint32 ModifyFpExc(TUint32 aClearMask, TUint32 aSetMask); sl@0: sl@0: void CompleteContextSave(); sl@0: }; sl@0: sl@0: sl@0: struct SArmInterruptInfo sl@0: { sl@0: TLinAddr iIrqHandler; sl@0: TLinAddr iFiqHandler; sl@0: SCpuIdleHandler iCpuIdleHandler; sl@0: }; sl@0: sl@0: extern "C" SArmInterruptInfo ArmInterruptInfo; sl@0: sl@0: #if defined(__ARMCC__) sl@0: #ifndef __CIA__ sl@0: inline void mb() sl@0: { sl@0: TUint32 reg = 0; sl@0: asm("mcr p15, 0, reg, c7, c10, 5 "); sl@0: } sl@0: sl@0: inline void arm_dsb() sl@0: { sl@0: TUint32 reg = 0; sl@0: asm("mcr p15, 0, reg, c7, c10, 4 "); sl@0: } sl@0: sl@0: inline void arm_isb() sl@0: { sl@0: TUint32 reg = 0; sl@0: asm("mcr p15, 0, reg, c7, c5, 4 "); sl@0: } sl@0: #endif sl@0: #elif defined(__GNUC__) || defined(__GCC32__) sl@0: #define mb() \ sl@0: do { \ sl@0: TUint32 reg = 0; \ sl@0: __asm__ __volatile__("mcr p15, 0, %0, c7, c10, 5" : : "r"(reg) : "memory"); \ sl@0: } while(0) sl@0: sl@0: #define arm_dsb() \ sl@0: do { \ sl@0: TUint32 reg = 0; \ sl@0: __asm__ __volatile__("mcr p15, 0, %0, c7, c10, 4" : : "r"(reg) : "memory"); \ sl@0: } while(0) sl@0: sl@0: #define arm_isb() \ sl@0: do { \ sl@0: TUint32 reg = 0; \ sl@0: __asm__ __volatile__("mcr p15, 0, %0, c7, c5, 4" : : "r"(reg) : "memory"); \ sl@0: } while(0) sl@0: #else sl@0: #error Unknown ARM compiler sl@0: #endif sl@0: sl@0: #define smp_mb() mb() sl@0: #define wmb() mb() sl@0: #define smp_wmb() mb() sl@0: sl@0: #ifdef __IN_KERNEL__ sl@0: struct ArmScu; sl@0: struct GicDistributor; sl@0: struct GicCpuIfc; sl@0: struct ArmLocalTimer; sl@0: #define SCU (*(ArmScu*)TheScheduler.i_ScuAddr) sl@0: #define GIC_DIST (*(GicDistributor*)TheScheduler.i_GicDistAddr) sl@0: #define GIC_CPU_IFC (*(GicCpuIfc*)TheScheduler.i_GicCpuIfcAddr) sl@0: #define LOCAL_TIMER (*(ArmLocalTimer*)TheScheduler.i_LocalTimerAddr) sl@0: #endif sl@0: sl@0: sl@0: // End of file sl@0: #endif