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: // This will make sure that the changes in page tables are visible by H/W Page-Table Walk. sl@0: // Call this function when two and more consecutive entries in page table are changed. sl@0: // sl@0: // sl@0: sl@0: /** sl@0: FORCE_INLINE macro in GCC works differently from in VC and armcc. sl@0: */ sl@0: #ifdef _MSC_VER sl@0: #define REALLY_INLINE __forceinline sl@0: #else sl@0: #ifdef __GNUC__ sl@0: #if __GNUC__ < 3 sl@0: #define REALLY_INLINE inline sl@0: #else sl@0: #define REALLY_INLINE inline __attribute__ ((always_inline)) sl@0: #endif sl@0: #else sl@0: #define REALLY_INLINE inline sl@0: #endif sl@0: #endif sl@0: sl@0: /** sl@0: This will make sure that the change in page directory is visible by H/W Page-Table Walk. sl@0: Call this function when a single entry in page directory is changed. sl@0: */ sl@0: extern void SinglePdeUpdated(TPde* aPde); sl@0: sl@0: sl@0: extern void __fastcall DoInvalidateTLBForPage(TLinAddr aLinAddrAndAsid); sl@0: extern void DoInvalidateTLB(); sl@0: sl@0: sl@0: /** sl@0: Invalidate a single I+D TLB entry on this CPU core only. sl@0: @param aLinAddrAndAsid Virtual address of a page of memory ORed with the ASID value. sl@0: */ sl@0: REALLY_INLINE void __fastcall LocalInvalidateTLBForPage(TLinAddr aLinAddrAndAsid) sl@0: { sl@0: DoInvalidateTLBForPage(aLinAddrAndAsid); sl@0: } sl@0: sl@0: sl@0: #ifndef __SMP__ sl@0: sl@0: /** sl@0: Invalidate a single I+D TLB entry sl@0: @param aLinAddrAndAsid Virtual address of a page of memory ORed with the ASID value. sl@0: */ sl@0: REALLY_INLINE void __fastcall InvalidateTLBForPage(TLinAddr aLinAddrAndAsid) sl@0: { sl@0: DoInvalidateTLBForPage(aLinAddrAndAsid); sl@0: } sl@0: sl@0: sl@0: /** sl@0: Invalidate entire TLB sl@0: */ sl@0: REALLY_INLINE void InvalidateTLB() sl@0: { sl@0: DoInvalidateTLB(); sl@0: } sl@0: sl@0: sl@0: #else // __SMP__ sl@0: sl@0: sl@0: #define COARSE_GRAINED_TLB_MAINTENANCE sl@0: sl@0: /** sl@0: Invalidate a single I+D TLB entry. sl@0: @param aLinAddrAndAsid Virtual address of a page of memory ORed with the ASID value. sl@0: */ sl@0: extern void InvalidateTLBForPage(TLinAddr aLinAddrAndAsid); sl@0: sl@0: sl@0: /** sl@0: Invalidate entire TLB sl@0: */ sl@0: extern void InvalidateTLB(); sl@0: sl@0: sl@0: #endif // __SMP__ sl@0: sl@0: sl@0: /** sl@0: Invalidate all TLB entries which match the given ASID value sl@0: */ sl@0: extern void InvalidateTLBForAsid(TUint aAsid); sl@0: sl@0: sl@0: FORCE_INLINE TPde* Mmu::PageDirectory(TInt aOsAsid) sl@0: { sl@0: return (TPde*)(KPageDirectoryBase+(aOsAsid<>KChunkShift); sl@0: } sl@0: sl@0: sl@0: FORCE_INLINE TPhysAddr Mmu::PdePhysAddr(TPde aPde) sl@0: { sl@0: if ((aPde&(KPdePtePresent|KPdeLargePage)) == (KPdePtePresent|KPdeLargePage)) sl@0: return aPde & KPdeLargePagePhysAddrMask; sl@0: return KPhysAddrInvalid; sl@0: } sl@0: sl@0: sl@0: FORCE_INLINE TPte Mmu::MakePteInaccessible(TPte aPte, TBool aReadOnly) sl@0: { sl@0: if(aReadOnly) sl@0: return aPte&~KPdePteWrite; sl@0: else sl@0: return aPte&~KPdePtePresent; sl@0: } sl@0: sl@0: sl@0: FORCE_INLINE TPte Mmu::MakePteAccessible(TPte aPte, TBool aWrite) sl@0: { sl@0: if((aPte&KPdePtePresent)==0) sl@0: { sl@0: aPte |= KPdePtePresent; sl@0: aPte &= ~KPdePteWrite; sl@0: } sl@0: if(aWrite) sl@0: aPte |= KPdePteWrite; sl@0: return aPte; sl@0: } sl@0: sl@0: sl@0: FORCE_INLINE TBool Mmu::IsPteReadOnly(TPte aPte) sl@0: { sl@0: __NK_ASSERT_DEBUG(aPte&KPdePtePresent); // read-only state is ambiguous if pte not present sl@0: return !(aPte&KPdePteWrite); sl@0: } sl@0: sl@0: sl@0: FORCE_INLINE TBool Mmu::IsPteInaccessible(TPte aPte) sl@0: { sl@0: return !(aPte&KPdePtePresent); sl@0: } sl@0: sl@0: sl@0: FORCE_INLINE TBool Mmu::IsPteMoreAccessible(TPte aNewPte, TPte aOldPte) sl@0: { sl@0: if(aNewPte&aOldPte&KPdePtePresent) // if ptes both present sl@0: return (aNewPte&~aOldPte)&KPdePteWrite; // check for more writable sl@0: else // else sl@0: return aNewPte&KPdePtePresent; // check for new pte being present sl@0: } sl@0: sl@0: sl@0: enum TPdeType sl@0: { sl@0: ENumPdeTypes = 1 sl@0: }; sl@0: sl@0: sl@0: enum TPteType sl@0: { sl@0: EPteTypeUserAccess = EUser, sl@0: EPteTypeWritable = EReadWrite, sl@0: EPteTypeGlobal = 1<<2, sl@0: ENumPteTypes = 8 sl@0: }; sl@0: sl@0: __ASSERT_COMPILE(EPteTypeUserAccess==(1<<0)); sl@0: __ASSERT_COMPILE(EPteTypeWritable==(1<<1)); sl@0: sl@0: sl@0: FORCE_INLINE TUint Mmu::PdeType(TMemoryAttributes /*aAttributes*/) sl@0: { sl@0: return 0; sl@0: } sl@0: sl@0: sl@0: FORCE_INLINE TUint Mmu::PteType(TMappingPermissions aPermissions, TBool aGlobal) sl@0: { sl@0: __NK_ASSERT_DEBUG(aPermissions&EUser || aGlobal); // can't have supervisor local memory sl@0: sl@0: TUint pteType = (aPermissions&(EUser|EReadWrite)); sl@0: if(aGlobal) sl@0: pteType |= EPteTypeGlobal; sl@0: sl@0: __NK_ASSERT_DEBUG(pteType