os/kernelhwsrv/kernel/eka/nkern/arm/ncutilf.cia
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     1 // Copyright (c) 1998-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\ncutilf.cia
    15 // 
    16 //
    17 
    18 #include <e32cia.h>
    19 #include <arm.h>
    20 #include "highrestimer.h"
    21 
    22 #ifdef __SCHEDULER_MACHINE_CODED__
    23 /** Signals the request semaphore of a nanothread.
    24 
    25 	This function is intended to be used by the EPOC layer and personality
    26 	layers.  Device drivers should use Kern::RequestComplete instead.
    27 
    28 	@param aThread Nanothread to signal.  Must be non NULL.
    29 
    30 	@see Kern::RequestComplete()
    31 
    32 	@pre Interrupts must be enabled.
    33 	@pre Do not call from an ISR.
    34  */
    35 EXPORT_C __NAKED__ void NKern::ThreadRequestSignal(NThread* /*aThread*/)
    36 	{
    37 	ASM_CHECK_PRECONDITIONS(MASK_INTERRUPTS_ENABLED|MASK_NOT_ISR);
    38 
    39 	asm("ldr r2, __TheScheduler ");
    40 	asm("str lr, [sp, #-4]! ");
    41 	asm("ldr r3, [r2, #%a0]" : : "i" _FOFF(TScheduler,iKernCSLocked));
    42 	asm("add r0, r0, #%a0" : : "i" _FOFF(NThread,iRequestSemaphore));
    43 	asm("add r3, r3, #1 ");
    44 	asm("str r3, [r2, #%a0]" : : "i" _FOFF(TScheduler,iKernCSLocked));
    45 	asm("bl  " CSM_ZN14NFastSemaphore6SignalEv);	// alignment OK since target is also assembler
    46 	asm("ldr lr, [sp], #4 ");
    47 	asm("b  " CSM_ZN5NKern6UnlockEv);
    48 	}
    49 
    50 
    51 /** Atomically signals the request semaphore of a nanothread and a fast mutex.
    52 
    53 	This function is intended to be used by the EPOC layer and personality
    54 	layers.  Device drivers should use Kern::RequestComplete instead.
    55 
    56 	@param aThread Nanothread to signal.  Must be non NULL.
    57 	@param aMutex Fast mutex to signal.  If NULL, the system lock is signaled.
    58 
    59 	@see Kern::RequestComplete()
    60 
    61 	@pre Kernel must be unlocked.
    62 	@pre Call in a thread context.
    63 	@pre Interrupts must be enabled.
    64  */
    65 EXPORT_C __NAKED__ void NKern::ThreadRequestSignal(NThread* /*aThread*/, NFastMutex* /*aMutex*/)
    66 	{
    67 	ASM_CHECK_PRECONDITIONS(MASK_INTERRUPTS_ENABLED|MASK_KERNEL_UNLOCKED|MASK_NOT_ISR|MASK_NOT_IDFC);
    68 
    69 	asm("ldr r2, __TheScheduler ");
    70 	asm("cmp r1, #0 ");
    71 	asm("ldreq r1, __SystemLock ");
    72 	asm("ldr r3, [r2, #%a0]" : : "i" _FOFF(TScheduler,iKernCSLocked));
    73 	asm("stmfd sp!, {r1,lr} ");
    74 	asm("add r0, r0, #%a0" : : "i" _FOFF(NThread,iRequestSemaphore));
    75 	asm("add r3, r3, #1 ");
    76 	asm("str r3, [r2, #%a0]" : : "i" _FOFF(TScheduler,iKernCSLocked));
    77 	asm("bl  " CSM_ZN14NFastSemaphore6SignalEv);
    78 	asm("ldr r0, [sp], #4 ");
    79 	asm("bl  " CSM_ZN10NFastMutex6SignalEv);		// alignment OK since target is also assembler
    80 	asm("ldr lr, [sp], #4 ");
    81 	asm("b  " CSM_ZN5NKern6UnlockEv);
    82 
    83 	asm("__SystemLock: ");
    84 	asm(".word %a0" : : "i" ((TInt)&TheScheduler.iLock));
    85 	asm("__TheScheduler: ");
    86 	asm(".word TheScheduler ");
    87 	}
    88 #endif
    89 
    90 
    91 #ifndef __USER_CONTEXT_TYPE_MACHINE_CODED__
    92 // called by C++ version of NThread::UserContextType()
    93 __NAKED__ TBool RescheduledAfterInterrupt(TUint32 /*aAddr*/)
    94 	{
    95 	asm("ldr r1, __irq_resched_return ");
    96 	asm("cmp r0, r1 ");
    97 	asm("movne r0, #0 ");
    98 	__JUMP(,lr);
    99 	asm("__irq_resched_return: ");
   100 	asm(".word irq_resched_return ");
   101 	}
   102 
   103 #else
   104 
   105 /** Get a value which indicates where a thread's user mode context is stored.
   106 
   107 	@return A value that can be used as an index into the tables returned by
   108 	NThread::UserContextTables().
   109 
   110 	@pre any context
   111 	@pre kernel locked
   112 	@post kernel locked
   113  
   114 	@see UserContextTables
   115 	@publishedPartner
   116  */
   117 EXPORT_C __NAKED__ NThread::TUserContextType NThread::UserContextType()
   118 	{
   119 	ASM_CHECK_PRECONDITIONS(MASK_KERNEL_LOCKED|MASK_NOT_ISR);
   120 //
   121 // Optimisation note: It may be possible to coalesce the first and second
   122 // checks below by creating separate "EContextXxxDied" context types for each
   123 // possible way a thread can die and ordering these new types before
   124 // EContextException.
   125 //
   126 
   127 	// Dying thread? use context saved earlier by kernel
   128 
   129 	asm("ldr r3, [r0, #%a0]" : : "i" _FOFF(NThread,iCsFunction));
   130 	asm("ldrb r2, [r0, #%a0]" : : "i" _FOFF(NThread,iSpare3));   // r2 = iUserContextType
   131 	asm("mov r1, r0 ");    // r1 = this
   132 	asm("cmp r3, #%a0" : : "i" ((TInt)NThread::ECSExitInProgress));
   133 	asm("moveq r0, r2"); 
   134 	__JUMP(eq,lr);
   135 
   136 	// Exception or no user context?
   137 
   138 	asm("ldr r3, __TheScheduler");
   139 	asm("cmp r2, #%a0 " : : "i" ((TInt)NThread::EContextException));
   140 	asm("ldr r3, [r3, #%a0]" : : "i" _FOFF(TScheduler,iCurrentThread));
   141 	asm("movls r0, r2 ");  // Return EContextNone or EContextException
   142 	__JUMP(ls,lr);
   143 	asm("cmp r2, #%a0 " : : "i" ((TInt)NThread::EContextUserIntrCallback));
   144 	asm("blo 1f");
   145 	asm("cmp r2, #%a0 " : : "i" ((TInt)NThread::EContextWFARCallback));
   146 	asm("movls r0, r2 ");  // Return EContextUserIntrCallback or EContextWFARCallback
   147 	__JUMP(ls,lr);
   148 
   149 	// Getting current thread context? must be in exec call as exception
   150 	// and dying thread cases were tested above.
   151 
   152 	asm("1: ");
   153 	asm("cmp r3, r1");
   154 	asm("moveq r0, #%a0" : : "i" ((TInt)NThread::EContextExec));
   155 	__JUMP(eq,lr);
   156 
   157 	asm("ldr r0, [r1, #%a0]" : : "i" _FOFF(NThread,iStackBase));
   158 	asm("ldr r2, [r1, #%a0]" : : "i" _FOFF(NThread,iStackSize));
   159 	asm("ldr r3, [r1, #%a0]" : : "i" _FOFF(NThread,iSavedSP));
   160 	asm("add r2, r2, r0");
   161 	asm("ldr r0, [r3, #%a0]" : : "i" (EXTRA_STACK_SPACE+11*4)); // get saved return address from reschedule
   162 	asm("ldr r12, __irq_resched_return ");
   163 	asm("sub r2, r2, r3");
   164 	asm("cmp r0, r12 ");
   165 	asm("beq preempted ");
   166 
   167 	// Transition to supervisor mode must have been due to a SWI
   168 
   169 	asm("not_preempted:");
   170 	asm("cmp r2, #%a0 " : : "i" ((TInt)(EXTRA_STACK_SPACE+15*4)));
   171 	asm("moveq r0, #%a0 " : : "i" ((TInt)NThread::EContextWFAR)); // thread must have blocked doing Exec::WaitForAnyRequest
   172 	asm("movne r0, #%a0 " : : "i" ((TInt)NThread::EContextExec)); // Thread must have been in a SLOW or UNPROTECTED Exec call
   173 	__JUMP(,lr);
   174 	
   175 	// thread was preempted due to an interrupt
   176 	// interrupt and reschedule will have pushed ? words + USER_MEMORY_GUARD_SAVE_WORDS + EXTRA_STACK_SPACE onto the stack
   177 
   178 	asm("preempted:");
   179 	asm("ldr r12, [r3, #%a0]" : : "i" (EXTRA_STACK_SPACE+USER_MEMORY_GUARD_SAVE_WORDS*4+12*4));  // first word on stack before reschedule
   180 	asm("mov r0, #%a0 " : : "i" ((TInt)NThread::EContextUserInterrupt));
   181 	asm("and r12, r12, #0x1f ");
   182 	asm("cmp r12, #0x10 ");   // interrupted mode = user?
   183 	__JUMP(eq,lr);
   184 
   185 	asm("cmp r2, #%a0 " : : "i" ((TInt)(EXTRA_STACK_SPACE+USER_MEMORY_GUARD_SAVE_WORDS*4+30*4)));
   186 	asm("bcs not_preempted "); 	// thread was interrupted in supervisor mode, return address and r4-r11 were saved
   187 
   188 	// interrupt occurred in exec call entry before r4-r11 saved
   189 	asm("cmp r2, #%a0 " : : "i" ((TInt)(EXTRA_STACK_SPACE+USER_MEMORY_GUARD_SAVE_WORDS*4+20*4)));
   190 	asm("moveq r0, #%a0 " : : "i" ((TInt)NThread::EContextSvsrInterrupt1)); // interrupt before return address was saved or after registers restored
   191 	asm("movne r0, #%a0 " : : "i" ((TInt)NThread::EContextSvsrInterrupt2)); // interrupt after return address saved
   192 	__JUMP(,lr);
   193 
   194 	asm("__irq_resched_return: ");
   195 	asm(".word irq_resched_return ");
   196 	}
   197 
   198 #endif  // __USER_CONTEXT_TYPE_MACHINE_CODED__
   199 
   200 __NAKED__ void Arm::GetUserSpAndLr(TAny*) 
   201 	{
   202 	asm("stmia r0, {r13, r14}^ ");
   203 	asm("mov r0, r0"); // NOP needed between stm^ and banked register access
   204 	__JUMP(,lr);
   205 	}
   206 
   207 __NAKED__ void Arm::SetUserSpAndLr(TAny*) 
   208 	{
   209 	asm("ldmia r0, {r13, r14}^ ");
   210 	asm("mov r0, r0"); // NOP needed between ldm^ and banked register access
   211 	__JUMP(,lr);
   212 	}
   213 
   214 #ifdef __CPU_ARM_USE_DOMAINS
   215 __NAKED__ TUint32 Arm::Dacr()
   216 	{
   217 	asm("mrc p15, 0, r0, c3, c0, 0 ");
   218 	__JUMP(,lr);
   219 	}
   220 
   221 __NAKED__ void Arm::SetDacr(TUint32)
   222 	{
   223 	asm("mcr p15, 0, r0, c3, c0, 0 ");
   224 	CPWAIT(,r0);
   225 	__JUMP(,lr);
   226 	}
   227 
   228 __NAKED__ TUint32 Arm::ModifyDacr(TUint32, TUint32)
   229 	{
   230 	asm("mrc p15, 0, r2, c3, c0, 0 ");
   231 	asm("bic r2, r2, r0 ");
   232 	asm("orr r2, r2, r1 ");
   233 	asm("mcr p15, 0, r2, c3, c0, 0 ");
   234 	CPWAIT(,r0);
   235 	asm("mov r0, r2 ");
   236 	__JUMP(,lr);
   237 	}
   238 #endif
   239 
   240 #ifdef __CPU_HAS_COPROCESSOR_ACCESS_REG
   241 __NAKED__ void Arm::SetCar(TUint32)
   242 	{
   243 	SET_CAR(,r0);
   244 	CPWAIT(,r0);
   245 	__JUMP(,lr);
   246 	}
   247 #endif
   248 
   249 
   250 
   251 /** Get the CPU's coprocessor access register value
   252 
   253 @return The value of the CAR, 0 if CPU doesn't have CAR
   254 
   255 @publishedPartner
   256 @released
   257  */
   258 EXPORT_C __NAKED__ TUint32 Arm::Car()
   259 	{
   260 #ifdef __CPU_HAS_COPROCESSOR_ACCESS_REG
   261 	GET_CAR(,r0);
   262 #else
   263 	asm("mov r0, #0 ");
   264 #endif
   265 	__JUMP(,lr);
   266 	}
   267 
   268 
   269 
   270 /** Modify the CPU's coprocessor access register value
   271 	Does nothing if CPU does not have CAR.
   272 
   273 @param	aClearMask	Mask of bits to clear	(1 = clear this bit)
   274 @param	aSetMask	Mask of bits to set		(1 = set this bit)
   275 @return The original value of the CAR, 0 if CPU doesn't have CAR
   276 
   277 @publishedPartner
   278 @released
   279  */
   280 EXPORT_C __NAKED__ TUint32 Arm::ModifyCar(TUint32 /*aClearMask*/, TUint32 /*aSetMask*/)
   281 	{
   282 #ifdef __CPU_HAS_COPROCESSOR_ACCESS_REG
   283 	GET_CAR(,r2);
   284 	asm("bic r0, r2, r0 ");
   285 	asm("orr r0, r0, r1 ");
   286 	SET_CAR(,r0);
   287 	CPWAIT(,r0);
   288 	asm("mov r0, r2 ");
   289 #else
   290 	asm("mov r0, #0 ");
   291 #endif
   292 	__JUMP(,lr);
   293 	}
   294 
   295 #ifdef __CPU_HAS_VFP
   296 __NAKED__ void Arm::SetFpExc(TUint32)
   297 	{
   298 #if defined(__CPU_ARM1136__) && !defined(__CPU_ARM1136_ERRATUM_351912_FIXED)
   299 // If we are about to enable VFP, disable dynamic branch prediction
   300 // If we are about to disable VFP, enable dynamic branch prediction if return stack prediction is enabled
   301 	asm("mrs r3, cpsr ");
   302 	CPSIDAIF;
   303 	asm("mrc p15, 0, r1, c1, c0, 1 ");
   304 	asm("tst r0, #%a0" : : "i" ((TInt)VFP_FPEXC_EN) );
   305 	asm("bic r1, r1, #2 ");				// clear DB bit (disable dynamic prediction)
   306 	asm("and r2, r1, #1 ");				// r2 bit 0 = RS bit (1 if return stack enabled)
   307 	asm("orreq r1, r1, r2, lsl #1 ");	// if VFP is being disabled set DB = RS
   308 	asm("mcr p15, 0, r1, c1, c0, 1 ");
   309 	asm("mcr p15, 0, r2, c7, c5, 6 ");	// flush BTAC
   310 	VFP_FMXR(,VFP_XREG_FPEXC,0);
   311 	asm("msr cpsr, r3 ");
   312 	__JUMP(,lr);
   313 #else
   314 	VFP_FMXR(,VFP_XREG_FPEXC,0);
   315 	__JUMP(,lr);
   316 #endif
   317 	}
   318 #endif
   319 
   320 
   321 
   322 /** Get the value of the VFP FPEXC register
   323 
   324 @return The value of FPEXC, 0 if there is no VFP
   325 
   326 @publishedPartner
   327 @released
   328  */
   329 EXPORT_C __NAKED__ TUint32 Arm::FpExc()
   330 	{
   331 #ifdef __CPU_HAS_VFP
   332 	VFP_FMRX(,0,VFP_XREG_FPEXC);
   333 #else
   334 	asm("mov r0, #0 ");
   335 #endif
   336 	__JUMP(,lr);
   337 	}
   338 
   339 
   340 
   341 /** Modify the VFP FPEXC register
   342 	Does nothing if there is no VFP
   343 
   344 @param	aClearMask	Mask of bits to clear	(1 = clear this bit)
   345 @param	aSetMask	Mask of bits to set		(1 = set this bit)
   346 @return The original value of FPEXC, 0 if no VFP present
   347 
   348 @publishedPartner
   349 @released
   350  */
   351 EXPORT_C __NAKED__ TUint32 Arm::ModifyFpExc(TUint32 /*aClearMask*/, TUint32 /*aSetMask*/)
   352 	{
   353 #ifdef __CPU_HAS_VFP
   354 	VFP_FMRX(,12,VFP_XREG_FPEXC);
   355 	asm("bic r0, r12, r0 ");
   356 	asm("orr r0, r0, r1 ");
   357 
   358 #if defined(__CPU_ARM1136__) && !defined(__CPU_ARM1136_ERRATUM_351912_FIXED)
   359 // If we are about to enable VFP, disable dynamic branch prediction
   360 // If we are about to disable VFP, enable dynamic branch prediction if return stack prediction is enabled
   361 	asm("mrs r3, cpsr ");
   362 	CPSIDAIF;
   363 	asm("mrc p15, 0, r1, c1, c0, 1 ");
   364 	asm("tst r0, #%a0" : : "i" ((TInt)VFP_FPEXC_EN) );
   365 	asm("bic r1, r1, #2 ");				// clear DB bit (disable dynamic prediction)
   366 	asm("and r2, r1, #1 ");				// r2 bit 0 = RS bit (1 if return stack enabled)
   367 	asm("orreq r1, r1, r2, lsl #1 ");	// if VFP is being disabled set DB = RS
   368 	asm("mcr p15, 0, r1, c1, c0, 1 ");
   369 	asm("mcr p15, 0, r2, c7, c5, 6 ");	// flush BTAC
   370 	VFP_FMXR(,VFP_XREG_FPEXC,0);
   371 	asm("msr cpsr, r3 ");
   372 #else
   373 	VFP_FMXR(,VFP_XREG_FPEXC,0);
   374 #endif	// erratum 351912
   375 
   376 	asm("mov r0, r12 ");
   377 #else	// no vfp
   378 	asm("mov r0, #0 ");
   379 #endif
   380 	__JUMP(,lr);
   381 	}
   382 
   383 /** Get the value of the VFP FPSCR register
   384 
   385 @return The value of FPSCR, 0 if there is no VFP
   386 
   387 @publishedPartner
   388 @released
   389  */
   390 EXPORT_C __NAKED__ TUint32 Arm::FpScr()
   391 	{
   392 #ifdef __CPU_HAS_VFP
   393 	VFP_FMRX(,0,VFP_XREG_FPSCR);
   394 #else
   395 	asm("mov r0, #0 ");
   396 #endif
   397 	__JUMP(,lr);
   398 	}
   399 
   400 
   401 
   402 /** Modify the VFP FPSCR register
   403 	Does nothing if there is no VFP
   404 
   405 @param	aClearMask	Mask of bits to clear	(1 = clear this bit)
   406 @param	aSetMask	Mask of bits to set		(1 = set this bit)
   407 @return The original value of FPSCR, 0 if no VFP present
   408 
   409 @publishedPartner
   410 @released
   411  */
   412 EXPORT_C __NAKED__ TUint32 Arm::ModifyFpScr(TUint32 /*aClearMask*/, TUint32 /*aSetMask*/)
   413 	{
   414 #ifdef __CPU_HAS_VFP
   415 	VFP_FMRX(,2,VFP_XREG_FPSCR);
   416 	asm("bic r0, r2, r0 ");
   417 	asm("orr r0, r0, r1 ");
   418 	VFP_FMXR(,VFP_XREG_FPSCR,0);
   419 	asm("mov r0, r2 ");
   420 #else
   421 	asm("mov r0, #0 ");
   422 #endif
   423 	__JUMP(,lr);
   424 	}
   425 
   426 
   427 /** Detect whether NEON is present
   428 
   429 @return ETrue if present, EFalse if not
   430 
   431 @internalTechnology
   432 @released
   433  */
   434 #if defined(__CPU_HAS_VFP) && defined(__VFP_V3)
   435 __NAKED__ TBool Arm::NeonPresent()
   436 	{
   437 	asm("mov	r0, #0 ");										// Not present
   438 	VFP_FMRX(,	1,VFP_XREG_FPEXC);								// Save VFP state
   439 	asm("orr	r2, r1, #%a0" : : "i" ((TInt)VFP_FPEXC_EN));
   440 	VFP_FMXR(,	VFP_XREG_FPEXC,1);								// Enable VFP
   441 
   442 	VFP_FMRX(,	2,VFP_XREG_MVFR0);								// Read MVFR0
   443 	asm("tst	r2, #%a0" : : "i" ((TInt)VFP_MVFR0_ASIMD32));	// Check to see if all 32 Advanced SIMD registers are present
   444 	asm("beq	0f ");											// Skip ahead if not
   445 	GET_CAR(,	r2);
   446 	asm("tst	r2, #%a0" : : "i" ((TInt)VFP_CPACR_ASEDIS));	// Check to see if ASIMD is disabled
   447 	asm("bne	0f ");											// Skip ahead if so
   448 	asm("tst	r2, #%a0" : : "i" ((TInt)VFP_CPACR_D32DIS));	// Check to see if the upper 16 registers are disabled
   449 	asm("moveq	r0, #1" );										// If not then eport NEON present
   450 
   451 	asm("0: ");
   452 	VFP_FMXR(,VFP_XREG_FPEXC,1);								// Restore VFP state
   453 	__JUMP(,	lr);
   454 	}
   455 #endif
   456 
   457 
   458 #ifdef __CPU_HAS_MMU
   459 __NAKED__ TBool Arm::MmuActive()
   460 	{
   461 	asm("mrc p15, 0, r0, c1, c0, 0 ");
   462 	asm("and r0, r0, #1 ");
   463 	__JUMP(,lr);
   464 	}
   465 
   466 // Returns the content of Translate Table Base Register 0.
   467 // To get physical address of the level 1 table, on some platforms this must be orred with 0xffff8000 (to get rid of table walk cache attributes)
   468 __NAKED__ TUint32 Arm::MmuTTBR0()
   469 	{
   470 	asm("mrc p15, 0, r0, c2, c0, 0 ");
   471 	__JUMP(,lr);
   472 	}
   473 #endif
   474 
   475 
   476 
   477 /** Get the current value of the high performance counter.
   478 
   479     If a high performance counter is not available, this uses the millisecond
   480     tick count instead.
   481 */
   482 #ifdef HAS_HIGH_RES_TIMER
   483 EXPORT_C __NAKED__ TUint32 NKern::FastCounter()
   484 	{
   485 	GET_HIGH_RES_TICK_COUNT(R0);
   486 	__JUMP(,lr);
   487 	}
   488 #else
   489 EXPORT_C TUint32 NKern::FastCounter()
   490 	{
   491 	return NTickCount();
   492 	}
   493 #endif
   494 
   495 
   496 
   497 /** Get the frequency of counter queried by NKern::FastCounter().
   498 */
   499 EXPORT_C TInt NKern::FastCounterFrequency()
   500 	{
   501 #ifdef HAS_HIGH_RES_TIMER
   502 	return KHighResTimerFrequency;
   503 #else
   504 	return 1000000 / NKern::TickPeriod();
   505 #endif
   506 	}
   507