kernel/eka/memmodel/epoc/multiple/arm/xsched.cia
author Tom Cosgrove <tom.cosgrove@nokia.com>
Fri, 28 May 2010 16:26:05 +0100
branchRCL_3
changeset 136 743008598095
parent 0 a41df078684a
permissions -rw-r--r--
Fix for bug 2283 (RVCT 4.0 support is missing from PDK 3.0.h) Have multiple extension sections in the bld.inf, one for each version of the compiler. The RVCT version building the tools will build the runtime libraries for its version, but make sure we extract all the other versions from zip archives. Also add the archive for RVCT4.

// Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the License "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
// e32\memmodel\epoc\multiple\arm\xsched.cia
// 
//

#include <e32cia.h>
#include <arm_mem.h>
#include "nk_cpu.h"

#define iMState		iWaitLink.iSpare1

//#define __DEBUG_BAD_ADDR

#ifdef __REQUEST_COMPLETE_MACHINE_CODED__
#if defined(_DEBUG)
extern "C" void __DebugMsgRequestComplete(TInt a0, TInt a1, TInt a2);
extern "C" void __DebugMsgReqCompleteWrite(TInt a0, TInt a1, TInt a2);
#endif

__NAKED__ void DThread::RequestComplete(TRequestStatus*& /*aStatus*/, TInt /*aReason*/)
//
// Signal this threads request semaphore.
// Enter with system locked, return with system unlocked.
//
	{
	ASM_DEBUG2(DThreadRequestComplete,r0,lr);
	
	asm("ldr r3, [r1] ");					// r3 points to TRequestStatus
	asm("mov r12, #0 ");
	asm("str r12, [r1] ");					// aStatus=NULL

	asm(".global _asm_RequestComplete ");
	asm("_asm_RequestComplete: ");

#ifdef BTRACE_REQUESTS
	asm("stmdb sp!,{r0-r3,lr}");
	asm("mov r1,r3");
	asm("mov r3,r2");											// arg3 = aReason
	asm("mov r2,r1");											// arg2 = aStatus
	asm("add r1,r0,#%a0" : : "i" _FOFF(DThread,iNThread));		// arg1 = &this->iNThread
	asm("ldr r0,_threadReqequestCompleteTraceHeader");			// arg0 = header
	asm("bl " CSM_ZN6BTrace4OutXEmmmm);
	asm("ldmia sp!,{r0-r3,lr}");
#endif

	ASM_DEBUG3(RequestComplete,r0,r3,r2);

	// r0 -> DThread, r3 -> TRequestStatus in user space, r2 = aReason
	asm("ldrb r12, [r0, #%a0]" : : "i" _FOFF(DThread,iMState));
	asm("ldr r1, __TheScheduler ");											// r1->TheScheduler
	asm("stmfd sp!, {r4-r9} ");
	asm("add r6, r0, #%a0" : : "i" _FOFF(DThread,iNThread));				// r6->target NThread
	asm("ldr r4, [r1, #%a0]" : : "i" _FOFF(TScheduler,iAddressSpace));		// r4->current process
	asm("ldr r0, [r0, #%a0]" : : "i" _FOFF(DThread,iOwningProcess));		// r0->target process
	asm("cmp r12, #%a0" : : "i" (DThread::EDead));	// test if iMState=EDead
	asm("beq req_complete_dead_thread ");	// if it is, finished
	asm("ldr r5, [r1, #%a0]" : : "i" _FOFF(TScheduler,iCurrentThread));		// r5->current NThread

	asm("mrc p15, 0, r7, c2, c0, 0 ");		// save TTBR0
	asm("ldr r9, [r0, #%a0]" : : "i" _FOFF(DMemModelProcess,iLocalPageDir));	// r9 -> target process page directory
	asm("ldr r8, [r0, #%a0]" : : "i" _FOFF(DMemModelProcess,iOsAsid));		// r8 = target ASID
	asm("and r12, r7, #%a0" : : "i" ((TInt)KTTBRExtraBitsMask));			// r12 = page table cache attributes
	asm("orr r9, r9, r12 ");				// r9 = target process TTBR0 value
	asm("mrs r12, cpsr ");					// save CPSR
	CPSIDAIF;								// disable all interrupts
	asm("mcr p15, 0, r12, c7, c10, 4 ");	// drain write buffer before changing MMU registers (see ARMv6 specs)
	UPDATE_PW_CACHING_ATTRIBUTES(,r9);		// ERRATUM 1136_317041
	asm("mcr p15, 0, r9, c2, c0, 0 ");		// change TTBR0
	asm("mcr p15, 0, r8, c13, c0, 1 ");		// change ASID

#if defined(__CPU_ARM11MP__)
	// On other platforms, tha ASID change above has already flushed the branch prediction buffers 
	asm("mcr p15, 0, r12, c7, c5, 6 ");		// flush BTAC
#endif

	asm("str r0, [r1, #%a0]" : : "i" _FOFF(TScheduler,iAddressSpace));
	asm("str r0, [r5, #%a0]" : : "i" _FOFF(NThread,iAddressSpace));
	asm("msr cpsr, r12 ");					// restore interrupts

	USER_MEMORY_GUARD_OFF(,r12,r12);
	asm(".global __magic_address_reqc ");	// NOTE: Z flag always clear here
	asm("__magic_address_reqc: ");			// this instruction is magically immune from exceptions
	asm("strt r2, [r3] ");					// store completion code with user permissions
											// MAY MODIFY Z and R12
	USER_MEMORY_GUARD_ON(,r12,r12);

	asm("mrs r12, cpsr ");					// save CPSR and Z flag which indicates whether write succeeded
	asm("ldr r2, [r4, #%a0]" : : "i" _FOFF(DMemModelProcess,iOsAsid));		// r2 = current process ASID
	CPSIDAIF;								// disable all interrupts
	asm("mcr p15, 0, r12, c7, c10, 4 ");	// drain write buffer before changing MMU registers (see ARMv6 specs)
	UPDATE_PW_CACHING_ATTRIBUTES(,r7);		// ERRATUM 1136_317041
	asm("mcr p15, 0, r7, c2, c0, 0 ");		// restore TTBR0
	asm("mcr p15, 0, r2, c13, c0, 1 ");		// restore ASID

#if defined(__CPU_ARM11MP__)
	// On other platforms, tha ASID change above has already flushed the branch prediction buffers 
	asm("mcr p15, 0, r12, c7, c5, 6 ");		// flush BTAC
#endif

	asm("str r4, [r1, #%a0]" : : "i" _FOFF(TScheduler,iAddressSpace));
	asm("str r4, [r5, #%a0]" : : "i" _FOFF(NThread,iAddressSpace));
	asm("msr cpsr, r12 ");					// restore interrupts and Z flag

#ifdef __DEBUG_BAD_ADDR
	asm("moveq r12, #0xde000000 ");
	asm("streq r12, [r12, #0xaf] ");		//HACK-CRASH SYSTEM IF WRITE FAILED
#endif

	asm("movne r0, r6 ");					// if write OK, r0->iNThread
	asm("req_complete_dead_thread: ");		// NOTE: Z flag set if thread dead
	asm("ldmfd sp!, {r4-r9} ");				// restore registers whether OK or not
	asm("movne r1, #0 ");
	asm("bne " CSM_ZN5NKern19ThreadRequestSignalEP7NThreadP10NFastMutex );
	asm("b " CSM_ZN5NKern12UnlockSystemEv);	// if any error, unlock system and return

#ifdef BTRACE_REQUESTS
	asm("_threadReqequestCompleteTraceHeader:");
	asm(".word %a0" : : "i" (BTRACE_HEADER_C(16,BTrace::ERequests,BTrace::ERequestComplete)));
#endif
	}
#endif

GLDEF_C __NAKED__ void DoProcessSwitch()
	{
	// Enter and return with kernel locked
	// r0->scheduler, r3->current thread
	// r5->old process, r9->new process
	// Return with r2 = (r2<<8) | ASID
	// Must preserve r0,r3, can modify other registers

	// This code is optimized with the ARM1136 static branch prediction scheme in mind.
	// Unusually, ARM1136 flushes the BTAC on every ContextID write whether it needs to 
	// or not!  We only need to flush the prefetch if there's differing local code... -jls

	asm("cmp r5, r9 ");						// check if current address space correct
	asm("beq address_switch_done");			// skip if address space change not required

	asm("mrc p15, 0, r1, c2, c0, 0 ");		// get TTBR0
	asm("ldr r4, [r9, #%a0]" : : "i" _FOFF(DMemModelProcess, iLocalPageDir));
	asm("and r1, r1, #%a0" : : "i" ((TInt)KTTBRExtraBitsMask));	// r1 = page table cache attributes
	asm("str r9, [r0, #%a0]" : : "i" _FOFF(TScheduler, iAddressSpace));
	asm("orr r4, r4, r1 ");					// r4 = new TTBR0 value
	asm("ldr r1, [r9, #%a0]" : : "i" _FOFF(DMemModelProcess, iSelfModChunks));
	asm("mcr p15, 0, r4, c7, c10, 4 ");		// drain write buffer before changing MMU registers (see ARMv6 specs)
	UPDATE_PW_CACHING_ATTRIBUTES(,r4);		// ERRATUM 1136_317041
	asm("mcr p15, 0, r4, c2, c0, 0 ");		// set TTBR0 - no TLB flush required due to ASID
	asm("cmp r1, #0");						// do we have selfmod chunks? (probably not)
	asm("bgt gotchunks ");					// yes, so we need to look closer (will predict not taken)

	asm("address_switch_done:");
	asm("ldr r4, [r9, #%a0]" : : "i" _FOFF(DMemModelProcess, iOsAsid));
	asm("ldr r6, [r3, #%a0]" : : "i" (_FOFF(DMemModelThread, iAliasLinAddr)-_FOFF(DThread, iNThread)) );
	asm("orr r2, r4, r2, lsl #8 ");			// r2 = original r2 << 8 | ASID
	asm("cmp r6, #0");						// check if thread has an alias in place
	asm("bne got_alias");
	__JUMP(,lr);

	// restore alias...
	asm("got_alias:");
	asm("ldr r7, [r3, #%a0]" : : "i" (_FOFF(DMemModelThread, iAliasPde)-_FOFF(DThread, iNThread)) );
	asm("ldr r1, [r0, #%a0]" : : "i" _FOFF(TScheduler, iExtras[1]));	// Alias remap old address
	asm("ldr r8, [r3, #%a0]" : : "i" (_FOFF(DMemModelThread, iAliasPdePtr)-_FOFF(DThread, iNThread)) );
	asm("orr r6, r6, r4");					// put ASID into address for TLB flush later...
	asm("eor r1, r1, r7 ");					// compare old address with pde
	asm("cmp r1, #0x1000 ");				// if result only has perm bits, addresses were the same
	asm("blo remap_alias ");

	asm("alias_remap_done: ");
	asm("str r7, [r8]");					// restore PDE for alias
	
	CACHE_MAINTENANCE_PDE_PTE_UPDATED(r8);
	
#ifdef __CPU_ARMV7
	UTLBIMVA(r6);
	ARM_DSBSH;
	ARM_ISBSY;
#else
	FLUSH_DTLB_ENTRY(,r6);					// flush TLB for aliased page
#endif
	__JUMP(,lr);

	asm("remap_alias: ");
	asm("ldr r7, [r0, #%a0]" : : "i" _FOFF(TScheduler, iExtras[2]));	// Alias remap new address
	asm("orr r7, r1, r7 ");					// r1 has perm bits, left over from xor above
	asm("b alias_remap_done ");

	asm("gotchunks: ");
	asm("ldr r1, [r0, #%a0]" : : "i" _FOFF(TScheduler, iExtras[0]));	// address of last selfmod process
	asm("cmp r1, r9");						// was it whoever's next up? (probably)
	asm("beq address_switch_done");
	asm("mcr p15, 0, r4, c7, c5, 4 ");		// prefetch flush before returning
#ifdef __CPU_HAS_UNFLUSHED_BTB
#ifdef __CPU_ARMV7
	BPIALL;
#else
	FLUSH_BTB(,r1);							// flush the dynamic branch predictor table
#endif
#endif
	asm("str r9, [r0, #%a0]" : : "i" _FOFF(TScheduler, iExtras[0]));	// update it 
	asm("b address_switch_done");

	asm("__TheScheduler: ");
	asm(".word TheScheduler ");
	};

/**
Restore the address space of the current thread so it matches its owning process.
*/
__NAKED__ void DMemModelThread::RestoreAddressSpace()
	{
	asm("ldr r12, __TheScheduler ");										// r12->TheScheduler
	asm("ldr r3, [r12, #%a0]" : : "i" _FOFF(TScheduler,iCurrentThread));	// r3->current NThread
	asm("ldr r0, [r3, #%a0]" : : "i" (-_FOFF(DThread,iNThread)+_FOFF(DThread,iOwningProcess)));		// r0->process

	// switch address space to process r0...
	asm("ldr r1, [r0, #%a0]" : : "i" _FOFF(DMemModelProcess,iLocalPageDir));// r1->process page directory
	asm("mrc p15, 0, r2, c2, c0, 0 ");		// get TTBR0
	asm("and r2, r2, #%a0" : : "i" ((TInt)KTTBRExtraBitsMask));	// r2 = page table cache attributes
	asm("orr r1, r1, r2 ");					// r1 = new TTBR0 value
	asm("ldr r2, [r0, #%a0]" : : "i" _FOFF(DMemModelProcess,iOsAsid));		// r2 = ASID
	CPSIDAIF;								// disable all interrupts
	asm("mcr p15, 0, r2, c7, c10, 4 ");	// drain write buffer before changing MMU registers (see ARMv6 specs)
	UPDATE_PW_CACHING_ATTRIBUTES(,r1);		// ERRATUM 1136_317041
	asm("mcr p15, 0, r1, c2, c0, 0 ");		// change TTBR0
	asm("mcr p15, 0, r2, c13, c0, 1 ");		// change ASID
	
#if defined(__CPU_ARM11MP__)
	// On other platforms, tha ASID change above has already flushed the branch prediction buffers 
	asm("mcr p15, 0, r2, c7, c5, 6 ");		// flush BTAC
#endif
	
	asm("str r0, [r12, #%a0]" : : "i" _FOFF(TScheduler,iAddressSpace));
	asm("str r0, [r3, #%a0]" : : "i" _FOFF(NThread,iAddressSpace));
	CPSIEAIF;								// enable all interrupts
	__JUMP(,lr);
	}