kernel/eka/memmodel/epoc/multiple/arm/xmmu.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\xmmu.cia
// 
//

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

#if defined(__CPU_ARM1136__) && !defined(__CPU_ARM1136_ERRATUM_353494_FIXED)
// This will also invalidate TLB entry if the third argument (asid) is specified (>=0).
// If asid is < 0, the caller is expected to deal with TLB invalidation.
__NAKED__ void remove_and_invalidate_page(TPte*, TLinAddr, TInt)
	{
	asm("stmfd sp!, {r4-r6,lr} ");
	asm("mov r6, r2 ");			//r6 = asid
	asm("mov r4, r0 ");
	asm("mov r5, #1 ");			//by default, one cache line to clean
	
	asm("ldr r3, [r0] ");		// r0 = original PTE
	asm("cmp r2, #0 ");
	asm("bicpl r1, r1, #0xff ");
	asm("orrpl r1, r1, r2 ");	// if ASID supplied, combine with VA
	asm("mrs r12, cpsr ");
	asm("mov r2, #0 ");
	CPSIDAIF;					// interrupts off
	asm("str r2, [r0], #4 ");	// clear PTE
	asm("tst r3, #3 ");			// PTE present?
	asm("beq 0f ");				// if not, done
	asm("tst r3, #2 ");			// small page?
	asm("bne 1f ");				// skip if small
	
	asm("mov r5, #2 ");			// there will be 2 cache lines to clean
	asm("mov r3, #0 ");
	asm("str r2, [r0], #4 ");
	asm("stmia r0!, {r2,r3} ");	// clear 16 consecutive PTEs
	asm("stmia r0!, {r2,r3} ");
	asm("stmia r0!, {r2,r3} ");
	asm("stmia r0!, {r2,r3} ");
	asm("stmia r0!, {r2,r3} ");
	asm("stmia r0!, {r2,r3} ");
	asm("stmia r0!, {r2,r3} ");
	
	asm("1: ");
#if defined(__CPU_PAGE_TABLES_FULLY_CACHED)
	// Clean the changed page table entries from the cache.
	// On ARM1136, cache line is always 32 bytes. 
	// For small page, a single cache line has to be cached.
	// For large page, 16 page table entries always fits into two cache lines
	CLEAN_DCACHE_LINE(,r4);		
	asm("subs r5, r5, #1");
	asm("addhi r4, r4, #32");// Clean the next cache line as well. Executes ...
	CLEAN_DCACHE_LINE(hi,r4);// ... only in case of large page table.
#endif
	
	asm("mcr p15, 0, r1, c7, c10, 4 ");	// drain write buffer
	asm("cmp r6, #0");				//is asid valid?

	FLUSH_DTLB_ENTRY(pl,r1);		// remove stale TLB entry if asid >= 0
	FLUSH_ITLB_ENTRY(pl,r1);

	asm("0: ");
	asm("msr cpsr, r12 ");
	asm("ldmfd sp!, {r4-r6,pc} ");		// if successful, exit
	}

// This will also invalidate TLB entry. (The third argument (asid) is assumed to be valid (>=0).)
__NAKED__ void remove_and_invalidate_section(TPde*, TLinAddr, TInt)
	{
	asm("ldr r3, [r0] ");		// r0 = original PDE
	asm("cmp r2, #0 ");
	asm("bicpl r1, r1, #0xff ");
	asm("orrpl r1, r1, r2 ");	// if ASID supplied, combine with VA
	asm("mrs r12, cpsr ");
	asm("mov r2, #0 ");
	CPSIDAIF;					// interrupts off
	asm("tst r3, #3 ");			// PDE present?
	asm("beq 0f ");				// if not, done
	asm("str r2, [r0] ");		// clear PDE
#if defined(__CPU_PAGE_TABLES_FULLY_CACHED)
	CLEAN_DCACHE_LINE(,r0);		
#endif
	asm("mcr p15, 0, r1, c7, c10, 4 ");	// drain write buffer
	FLUSH_DTLB_ENTRY(,r1);		// remove stale TLB entry
	FLUSH_ITLB_ENTRY(,r1);
	asm("0: ");
	asm("msr cpsr, r12 ");
	__JUMP(,lr);
	}
#endif


__NAKED__ void MakeGlobalPTEInaccessible(TPte* aPtePtr, TPte aNewPte, TLinAddr aLinAddr)
	{
	asm("mov r3,#0 ");
	// fall through
	}

__NAKED__ void MakePTEInaccessible(TPte* aPtePtr, TPte aNewPte, TLinAddr aLinAddr, TInt aAsid)
	{
	asm("bic r2, r2, #0xff ");
	asm("orr r2, r2, r3 ");
#if defined(__CPU_ARM1136__) && !defined(__CPU_ARM1136_ERRATUM_353494_FIXED)
	CPSIDIF;					// interrupts off
	asm("str r1,[r0]");
	#if defined(__CPU_PAGE_TABLES_FULLY_CACHED)
	CLEAN_DCACHE_LINE(,r0);		
	#endif
	DRAIN_WRITE_BUFFER(,r1,r1);
	FLUSH_DTLB_ENTRY(,r2);		// remove stale TLB entries
	FLUSH_ITLB_ENTRY(,r2);
	asm("mov r1, #0");
	FLUSH_BTB(,r1);
	CPSIEIF;					// interrupts on
#else
	asm("str r1,[r0]");
#if defined(__CPU_PAGE_TABLES_FULLY_CACHED)
#ifdef __CPU_ARMV7
	DCCMVAU(r0);
	ARM_DSBSH;
#else
	CLEAN_DCACHE_LINE(,r0);
	DRAIN_WRITE_BUFFER(,r1,r1);
#endif
#endif
#ifdef __CPU_ARMV7
	UTLBIMVA(r2);
	ARM_DSBSH;
	ARM_ISBSY;
#else
	FLUSH_DTLB_ENTRY(,r2);		// remove stale TLB entries
	FLUSH_ITLB_ENTRY(,r2);
#endif
#endif
	__JUMP(,lr);
	}


__NAKED__ void InvalidateTLBForPage(TLinAddr /*aLinAddr*/, TInt /*aAsid*/)
//
// Flush a specified virtual address from the TLB.
// If aAsid>0, flush is restricted to ASID=aAsid for non-global entries.
// If aAsid=0, Kernel asid is specified - will flush global entry or the entry belonging to local Kernel space.
// If aAsid<0, no ASID is specified - will flush all TLB entries with matching VA regardles of ASID (or whether they are
//									  local or global). In the absence of such MMU command, flush-entire-TLB will apply here.
	{
	asm("cmp r1, #0 ");
	asm("bmi 1f ");
	asm("bic r0, r0, #0xff ");		// if aAsid > 0, orr it with linear address in r0.
	asm("orr r0, r0, r1 ");
#ifdef __CPU_ARMV7
	UTLBIMVA(r0);
	ARM_DSBSH;
	ARM_ISBSY;
#else
	FLUSH_DTLB_ENTRY(,r0);
	FLUSH_ITLB_ENTRY(,r0);
#endif
	__JUMP(,lr);

	asm("1: ");
#ifdef __CPU_ARMV7
	UTLBIALL;
	ARM_DSBSH;
	ARM_ISBSY;
#else
	asm("mov r0, #0 ");
	FLUSH_IDTLB(,r0);				// aAsid < 0. There is no coprocessor instruction that will flush all ...
									// ... entries matching Linear address. Flush entire TLB instead and exit.
#endif
	__JUMP(,lr);
	}

__NAKED__ void FlushTLBs()
	{
#ifdef __CPU_ARMV7
	UTLBIALL;
	ARM_DSBSH;
	ARM_ISBSY;
#else
	asm("mov r0, #0 ");
	FLUSH_IDTLB(,r0);
#endif
	__JUMP(,lr);
	}

__NAKED__ TUint32 TTCR()
	{
	asm("mrc p15, 0, r0, c2, c0, 2 ");
	asm("and r0, r0, #7 ");	// only bottom 3 bits are defined
	__JUMP(,lr);
	}

GLDEF_C __NAKED__ void __FlushBtb()
	{
#ifdef __CPU_ARMV7
#ifdef __SMP__
	BPIALLIS;
#else 	//def __SMP__
	BPIALL;
#endif 	// else __SMP__
    ARM_DSBSH;
	ARM_ISBSY;
#else	//def __CPU_ARMV7
	asm("mov r1, #0");
	FLUSH_BTB(,r1);
#endif	//else __CPU_ARMV7
	__JUMP(,lr);
	}

// Generic cache/TLB flush function.
// Which things are flushed is determined by aMask.
__NAKED__ void ArmMmu::GenericFlush(TUint32 /*aMask*/)
	{
#ifdef __CPU_ARMV7
	asm("tst r1, #%a0" : : "i" (EFlushDTLB) );
	asm("tsteq r1, #%a0" : : "i" (EFlushDPermChg) );
	asm("tsteq r1, #%a0" : : "i" (EFlushITLB) );
	asm("tsteq r1, #%a0" : : "i" (EFlushIPermChg) );
	asm("beq 1f ");
	UTLBIALL;
	ARM_DSBSH;
	ARM_ISBSY;
	asm("1: ");
#else
	asm("mov r2, #0 ");
	asm("tst r1, #%a0" : : "i" (EFlushDTLB) );
	asm("tsteq r1, #%a0" : : "i" (EFlushDPermChg) );
	FLUSH_DTLB(ne,r2);
	asm("tst r1, #%a0" : : "i" (EFlushITLB) );
	asm("tsteq r1, #%a0" : : "i" (EFlushIPermChg) );
	FLUSH_ITLB(ne,r2);
#endif
	__JUMP(,lr);
	}

__NAKED__ void ExecHandler::UnlockRamDrive()
	{
	asm("ldr r0, [r1, #%a0]" : : "i" (_FOFF(DThread,iOwningProcess)-_FOFF(DThread,iNThread)));
	asm("ldr r0, [r0, #%a0]" : : "i" _FOFF(DProcess,iS.iCaps));
// __KERNEL_CAPABILITY_CHECK
	asm("tst r0, #%a0 " : : "i" ((TInt)(1<<ECapabilityTCB)));
	__JUMP(eq,lr);	   // don't unlock the RAM drive if don't have MediaDD capability

	// fall through to unlock
	}

EXPORT_C __NAKED__ void TInternalRamDrive::Unlock()
	{
	asm("mrc p15, 0, r0, c3, c0, 0 ");
	asm("bic r0, r0, #0x0c ");
	asm("orr r0, r0, #0x04 ");			// RAM drive in domain 1
	asm("mcr p15, 0, r0, c3, c0, 0 ");
	CPWAIT(,r0);
	__JUMP(,lr);
	}

EXPORT_C __NAKED__ void TInternalRamDrive::Lock()
	{
	asm("mrc p15, 0, r0, c3, c0, 0 ");
	asm("bic r0, r0, #0x0c ");			// RAM drive in domain 1
	asm("mcr p15, 0, r0, c3, c0, 0 ");
	CPWAIT(,r0);
	__JUMP(,lr);
	}

__NAKED__ void ArmMmu::UnlockAlias()
	{
	asm("mrc p15, 0, r0, c3, c0, 0 ");
	asm("orr r0, r0, #0x10 ");			// Alias memory in domain 2
	asm("mcr p15, 0, r0, c3, c0, 0 ");
	CPWAIT(,r0);
	__JUMP(,lr);
	}

__NAKED__ void ArmMmu::LockAlias()
	{
	asm("mrc p15, 0, r0, c3, c0, 0 ");
	asm("bic r0, r0, #0x30 ");			// Alias memory in domain 2
	asm("mcr p15, 0, r0, c3, c0, 0 ");
	CPWAIT(,r0);
	__JUMP(,lr);
	}


__NAKED__ void M::LockUserMemory()
	{
	USER_MEMORY_GUARD_ON(,r0,r0);
	__JUMP(,lr);
	}


__NAKED__ void M::UnlockUserMemory()
	{
	USER_MEMORY_GUARD_OFF(,r0,r0);
	__JUMP(,lr);
	}