kernel/eka/memmodel/epoc/flexible/mmu/arm/xmmu.cpp
changeset 0 a41df078684a
child 4 56f325a607ea
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     1 // Copyright (c) 1997-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 //
       
    15 
       
    16 #include "arm_mem.h"
       
    17 #include "mm.h"
       
    18 #include "mmu.h"
       
    19 #include "mpager.h"
       
    20 
       
    21 #include "cache_maintenance.inl"
       
    22 #include "execs.h"
       
    23 
       
    24 
       
    25 #ifdef BROADCAST_TLB_MAINTENANCE
       
    26 class TTLBIPI : public TGenericIPI
       
    27 	{
       
    28 public:
       
    29 	TTLBIPI();
       
    30 	static void InvalidateIsr(TGenericIPI*);
       
    31 	static void WaitAndInvalidateIsr(TGenericIPI*);
       
    32 	void AddArg(TLinAddr aArg);
       
    33 public:
       
    34 	volatile TInt	iFlag;
       
    35 	TLinAddr		iArg;
       
    36 	};
       
    37 
       
    38 TTLBIPI::TTLBIPI()
       
    39 	:	iFlag(0), iArg(0)
       
    40 	{
       
    41 	}
       
    42 
       
    43 void TTLBIPI::InvalidateIsr(TGenericIPI* aPtr)
       
    44 	{
       
    45 	TRACE2(("TLBInv"));
       
    46 	TTLBIPI& a = *(TTLBIPI*)aPtr;
       
    47 	TLinAddr arg = a.iArg;
       
    48 	if (arg==0)
       
    49 		LocalInvalidateTLB();
       
    50 	else if (arg<256)
       
    51 		LocalInvalidateTLBForAsid(arg);
       
    52 	else
       
    53 		LocalInvalidateTLBForPage(arg);
       
    54 	}
       
    55 
       
    56 void TTLBIPI::WaitAndInvalidateIsr(TGenericIPI* aPtr)
       
    57 	{
       
    58 	TRACE2(("TLBWtInv"));
       
    59 	TTLBIPI& a = *(TTLBIPI*)aPtr;
       
    60 	while (!a.iFlag)
       
    61 		{ __chill(); }
       
    62 	InvalidateIsr(aPtr);
       
    63 	}
       
    64 
       
    65 void TTLBIPI::AddArg(TLinAddr aArg)
       
    66 	{
       
    67 	iArg = aArg;
       
    68 	NKern::Lock();
       
    69 	InvalidateIsr(this);
       
    70 	QueueAllOther(&InvalidateIsr);
       
    71 	NKern::Unlock();
       
    72 	WaitCompletion();
       
    73 	}
       
    74 
       
    75 void BroadcastInvalidateTLB(TLinAddr aLinAddrAndAsid)
       
    76 	{
       
    77 	TTLBIPI ipi;
       
    78 	ipi.AddArg(aLinAddrAndAsid);
       
    79 	}
       
    80 #endif	// BROADCAST_TLB_MAINTENANCE
       
    81 
       
    82 //
       
    83 // Functions for class Mmu
       
    84 //
       
    85 
       
    86 /**
       
    87 Return the physical address of the memory mapped by a Page Table Entry (PTE).
       
    88 
       
    89 @param aPte			The value contained in the PTE.
       
    90 @param aPteIndex	The index of the PTE within its page table.
       
    91 */
       
    92 TPhysAddr Mmu::PtePhysAddr(TPte aPte, TUint aPteIndex)
       
    93 	{
       
    94 	if(aPte&KArmV6PteSmallPage)
       
    95 		return aPte & KPteSmallPageAddrMask;
       
    96 	if(aPte&KArmV6PteLargePage)
       
    97 		return (aPte & KPteLargePageAddrMask) + (TPhysAddr(aPteIndex << KPageShift) & KLargePageMask);
       
    98 	return KPhysAddrInvalid;
       
    99 	}
       
   100 
       
   101 
       
   102 /**
       
   103 Return the virtual address of the page table referenced by the given
       
   104 Page Directory Entry (PDE) \a aPde. If the PDE doesn't refer to a
       
   105 page table then the null-pointer is returned.
       
   106 
       
   107 If the page table was not one allocated by the kernel then the
       
   108 results are unpredictable and may cause a system fault.
       
   109 
       
   110 @pre #MmuLock held.
       
   111 */
       
   112 TPte* Mmu::PageTableFromPde(TPde aPde)
       
   113 	{
       
   114 	if((aPde&KPdePresentMask)==KArmV6PdePageTable)
       
   115 		{
       
   116 		SPageInfo* pi = SPageInfo::FromPhysAddr(aPde);
       
   117 		return (TPte*)(KPageTableBase+(pi->Index()<<KPageShift)+(aPde&(KPageMask&~KPageTableMask)));
       
   118 		}
       
   119 	return 0;
       
   120 	}
       
   121 
       
   122 
       
   123 /**
       
   124 Perform the action of #PageTableFromPde but without the possibility of
       
   125 a system fault caused the page table not being one allocated by the kernel.
       
   126 
       
   127 @pre #MmuLock held.
       
   128 */
       
   129 TPte* Mmu::SafePageTableFromPde(TPde aPde)
       
   130 	{
       
   131 	if((aPde&KPdeTypeMask)==KArmV6PdePageTable)
       
   132 		{
       
   133 		SPageInfo* pi = SPageInfo::SafeFromPhysAddr(aPde&~KPageMask);
       
   134 		if(pi)
       
   135 			return (TPte*)(KPageTableBase+(pi->Index()<<KPageShift)+(aPde&(KPageMask&~KPageTableMask)));
       
   136 		}
       
   137 	return 0;
       
   138 	}
       
   139 
       
   140 
       
   141 /**
       
   142 Return the base phsical address of the section table referenced by the given
       
   143 Page Directory Entry (PDE) \a aPde. If the PDE doesn't refer to a
       
   144 section then KPhysAddrInvalid is returned.
       
   145 
       
   146 @pre #MmuLock held.
       
   147 */
       
   148 TPhysAddr Mmu::SectionBaseFromPde(TPde aPde)
       
   149 	{
       
   150 	if(PdeMapsSection(aPde))
       
   151 		return aPde&KPdeSectionAddrMask;
       
   152 	return KPhysAddrInvalid;
       
   153 	}
       
   154 
       
   155 
       
   156 /**
       
   157 Return a pointer to the Page Table Entry (PTE) which maps the
       
   158 virtual address \a aAddress in the address space \a aOsAsid.
       
   159 
       
   160 If no page table exists or it was not one allocated by the kernel
       
   161 then the results are unpredictable and may cause a system fault.
       
   162 
       
   163 @pre #MmuLock held.
       
   164 */
       
   165 TPte* Mmu::PtePtrFromLinAddr(TLinAddr aAddress, TInt aOsAsid)
       
   166 	{
       
   167 	TPde pde = PageDirectory(aOsAsid)[aAddress>>KChunkShift];
       
   168 	SPageInfo* pi = SPageInfo::FromPhysAddr(pde);
       
   169 	TPte* pt = (TPte*)(KPageTableBase+(pi->Index()<<KPageShift)+(pde&(KPageMask&~KPageTableMask)));
       
   170 	pt += (aAddress>>KPageShift)&(KChunkMask>>KPageShift);
       
   171 	return pt;
       
   172 	}
       
   173 
       
   174 
       
   175 /**
       
   176 Perform the action of #PtePtrFromLinAddr but without the possibility
       
   177 of a system fault. If the page table is not present or not one
       
   178 allocated by the kernel then the null-pointer is returned.
       
   179 
       
   180 @pre #MmuLock held.
       
   181 */
       
   182 TPte* Mmu::SafePtePtrFromLinAddr(TLinAddr aAddress, TInt aOsAsid)
       
   183 	{
       
   184 	TPde pde = PageDirectory(aOsAsid)[aAddress>>KChunkShift];
       
   185 	TPte* pt = SafePageTableFromPde(pde);
       
   186 	if(pt)
       
   187 		pt += (aAddress>>KPageShift)&(KChunkMask>>KPageShift);
       
   188 	return pt;
       
   189 	}
       
   190 
       
   191 
       
   192 /**
       
   193 Return the physical address for the page table whose virtual
       
   194 address is \a aPt.
       
   195 
       
   196 If the page table was not one allocated by the kernel then the
       
   197 results are unpredictable and may cause a system fault.
       
   198 
       
   199 @pre #MmuLock held.
       
   200 */
       
   201 TPhysAddr Mmu::PageTablePhysAddr(TPte* aPt)
       
   202 	{
       
   203 	__NK_ASSERT_DEBUG(MmuLock::IsHeld() || PageTablesLockIsHeld());
       
   204 
       
   205 	TInt pdeIndex = ((TLinAddr)aPt)>>KChunkShift;
       
   206 	TPde pde = PageDirectory(KKernelOsAsid)[pdeIndex];
       
   207 	__NK_ASSERT_DEBUG((pde&KPdePresentMask)==KArmV6PdePageTable);
       
   208 
       
   209 	SPageInfo* pi = SPageInfo::FromPhysAddr(pde);
       
   210 	TPte* pPte = (TPte*)(KPageTableBase+(pi->Index(true)<<KPageShift)+(pde&(KPageMask&~KPageTableMask)));
       
   211 	TPte pte = pPte[(((TLinAddr)aPt)&KChunkMask)>>KPageShift];
       
   212 	__NK_ASSERT_DEBUG(pte & KArmV6PteSmallPage);
       
   213 
       
   214 	return (pte&KPteSmallPageAddrMask)|(((TLinAddr)aPt)&(KPageMask&~KPageTableMask));
       
   215 	}
       
   216 
       
   217 
       
   218 /**
       
   219 Perform a page table walk to return the physical address of
       
   220 the memory mapped at virtual address \a aLinAddr in the
       
   221 address space \a aOsAsid.
       
   222 
       
   223 If the page table used was not one allocated by the kernel
       
   224 then the results are unpredictable and may cause a system fault.
       
   225 
       
   226 Use of this function should be avoided, use instead Mmu::LinearToPhysical
       
   227 which contains debug assertions for its preconditions.
       
   228 
       
   229 @pre #MmuLock held.
       
   230 */
       
   231 TPhysAddr Mmu::UncheckedLinearToPhysical(TLinAddr aLinAddr, TInt aOsAsid)
       
   232 	{
       
   233 	TRACE2(("Mmu::UncheckedLinearToPhysical(%08x,%d)",aLinAddr,aOsAsid));
       
   234 	TInt pdeIndex = aLinAddr>>KChunkShift;
       
   235 	TPde pde = PageDirectory(aOsAsid)[pdeIndex];
       
   236 	if ((pde&KPdePresentMask)==KArmV6PdePageTable)
       
   237 		{
       
   238 		SPageInfo* pi = SPageInfo::FromPhysAddr(pde);
       
   239 		TPte* pPte = (TPte*)(KPageTableBase+(pi->Index(true)<<KPageShift)+(pde&(KPageMask&~KPageTableMask)));
       
   240 		TPte pte = pPte[(aLinAddr&KChunkMask)>>KPageShift];
       
   241 		if (pte & KArmV6PteSmallPage)
       
   242 			{
       
   243 			TPhysAddr pa=(pte&KPteSmallPageAddrMask)|(aLinAddr&~KPteSmallPageAddrMask);
       
   244 			__KTRACE_OPT(KMMU,Kern::Printf("Mapped with small page - returning %08x",pa));
       
   245 			return pa;
       
   246 			}
       
   247 		else if (pte & KArmV6PteLargePage)
       
   248 			{
       
   249 			TPhysAddr pa=(pte&KPteLargePageAddrMask)|(aLinAddr&~KPteLargePageAddrMask);
       
   250 			__KTRACE_OPT(KMMU,Kern::Printf("Mapped with large page - returning %08x",pa));
       
   251 			return pa;
       
   252 			}
       
   253 		}
       
   254 	else if ((pde&KPdePresentMask)==KArmV6PdeSection)
       
   255 		{
       
   256 		TPhysAddr pa=(pde&KPdeSectionAddrMask)|(aLinAddr&~KPdeSectionAddrMask);
       
   257 		__KTRACE_OPT(KMMU,Kern::Printf("Mapped with section - returning %08x",pa));
       
   258 		return pa;
       
   259 		}
       
   260 	return KPhysAddrInvalid;
       
   261 	}
       
   262 
       
   263 
       
   264 extern TUint32 TTCR();
       
   265 extern TUint32 CPUID(TInt /*aRegNum*/);
       
   266 
       
   267 
       
   268 void Mmu::Init1()
       
   269 	{
       
   270 	TRACEB(("Mmu::Init1"));
       
   271 
       
   272 	// check page local/global page directory split is correct...
       
   273 	__NK_ASSERT_ALWAYS(TTCR()==1);
       
   274 
       
   275 	// check cache type is supported and consistent with compile time macros...
       
   276 	TInt iColourCount = 0;
       
   277 	TInt dColourCount = 0;
       
   278 	TUint32 ctr = InternalCache::TypeRegister();
       
   279 	TRACEB(("CacheTypeRegister = %08x",ctr));
       
   280 #ifdef __CPU_ARMV6
       
   281 	__NK_ASSERT_ALWAYS((ctr>>29)==0);	// check ARMv6 format
       
   282 	if(ctr&0x800)
       
   283 		iColourCount = 4;
       
   284 	if(ctr&0x800000)
       
   285 		dColourCount = 4;
       
   286 #else
       
   287 	__NK_ASSERT_ALWAYS((ctr>>29)==4);	// check ARMv7 format
       
   288 	TUint l1ip = (ctr>>14)&3;			// L1 instruction cache indexing and tagging policy
       
   289 	__NK_ASSERT_ALWAYS(l1ip>=2);		// check I cache is physically tagged
       
   290 
       
   291 	TUint32 clidr = InternalCache::LevelIDRegister();
       
   292 	TRACEB(("CacheLevelIDRegister = %08x",clidr));
       
   293 	TUint l1type = clidr&7;
       
   294 	if(l1type)
       
   295 		{
       
   296 		if(l1type==2 || l1type==3 || l1type==4)
       
   297 			{
       
   298 			// we have an L1 data cache...
       
   299 			TUint32 csir = InternalCache::SizeIdRegister(0,0);
       
   300 			TUint sets = ((csir>>13)&0x7fff)+1;
       
   301 			TUint ways = ((csir>>3)&0x3ff)+1;
       
   302 			TUint lineSizeShift = (csir&7)+4;
       
   303 			// assume L1 data cache is VIPT and alias checks broken and so we need data cache colouring...
       
   304 			dColourCount = (sets<<lineSizeShift)>>KPageShift;
       
   305 			if(l1type==4) // unified cache, so set instruction cache colour as well...
       
   306 				iColourCount = (sets<<lineSizeShift)>>KPageShift;
       
   307 			TRACEB(("L1DCache = 0x%x,0x%x,%d colourCount=%d",sets,ways,lineSizeShift,(sets<<lineSizeShift)>>KPageShift));
       
   308 			}
       
   309 
       
   310 		if(l1type==1 || l1type==3)
       
   311 			{
       
   312 			// we have a separate L1 instruction cache...
       
   313 			TUint32 csir = InternalCache::SizeIdRegister(1,0);
       
   314 			TUint sets = ((csir>>13)&0x7fff)+1;
       
   315 			TUint ways = ((csir>>3)&0x3ff)+1;
       
   316 			TUint lineSizeShift = (csir&7)+4;
       
   317 			iColourCount = (sets<<lineSizeShift)>>KPageShift;
       
   318 			TRACEB(("L1ICache = 0x%x,0x%x,%d colourCount=%d",sets,ways,lineSizeShift,(sets<<lineSizeShift)>>KPageShift));
       
   319 			}
       
   320 		}
       
   321 	if(l1ip==3)
       
   322 		{
       
   323 		// PIPT cache, so no colouring restrictions...
       
   324 		TRACEB(("L1ICache is PIPT"));
       
   325 		iColourCount = 0;
       
   326 		}
       
   327 	else
       
   328 		{
       
   329 		// VIPT cache...
       
   330 		TRACEB(("L1ICache is VIPT"));
       
   331 		}
       
   332 #endif
       
   333 	TRACEB(("page colouring counts I=%d, D=%d",iColourCount,dColourCount));
       
   334 	__NK_ASSERT_ALWAYS(iColourCount<=KPageColourCount);
       
   335 	__NK_ASSERT_ALWAYS(dColourCount<=KPageColourCount);
       
   336 	#ifndef __CPU_I_CACHE_HAS_COLOUR
       
   337 	__NK_ASSERT_ALWAYS(iColourCount==0);
       
   338 	#endif
       
   339 	#ifndef __CPU_D_CACHE_HAS_COLOUR
       
   340 	__NK_ASSERT_ALWAYS(dColourCount==0);
       
   341 	#endif
       
   342 	#ifndef __CPU_CACHE_HAS_COLOUR
       
   343 	__NK_ASSERT_ALWAYS(iColourCount==0);
       
   344 	__NK_ASSERT_ALWAYS(dColourCount==0);
       
   345 	#endif
       
   346 
       
   347 	// check MMU attributes match our assumptions...
       
   348 	if(((CPUID(-1)>>16)&0xf)==0xf) // if have new CPUID format....
       
   349 		{
       
   350 		TUint mmfr1 = CPUID(5);
       
   351 		TRACEB(("mmfr1 = %08x",mmfr1));
       
   352 		#ifdef __CPU_NEEDS_BTAC_FLUSH_AFTER_ASID_CHANGE
       
   353 			__NK_ASSERT_ALWAYS(((mmfr1>>28)&0xf)==1); // Branch Predictor needs invalidating after ASID change
       
   354 		#else
       
   355 			__NK_ASSERT_ALWAYS(((mmfr1>>28)&0xf)>=2); // Branch Predictor doesn't needs invalidating after ASID change
       
   356 		#endif
       
   357 
       
   358 		TUint mmfr2 = CPUID(6);
       
   359 		TRACEB(("mmfr2 = %08x",mmfr2));
       
   360 		__NK_ASSERT_ALWAYS(((mmfr2>>20)&0xf)>=2); // check Mem Barrier instructions are supported in CP15
       
   361 
       
   362 		TUint mmfr3 = CPUID(7);
       
   363 		TRACEB(("mmfr3 = %08x",mmfr3));
       
   364 		(void)mmfr3;
       
   365 
       
   366 		#if defined(__SMP__) && !defined(__CPU_ARM11MP__)
       
   367 			__NK_ASSERT_ALWAYS(((mmfr3>>12)&0xf)>=2); // check Maintenance Broadcast is for all cache and TLB operations
       
   368 		#endif	
       
   369 		#ifdef __CPU_SUPPORTS_PAGE_TABLE_WALK_TO_L1_CACHE
       
   370 			__NK_ASSERT_ALWAYS(((mmfr3>>20)&0xf)>=1); // check Coherent Walk for page tables
       
   371 		#endif	
       
   372 		}
       
   373 
       
   374 	Arm::DefaultDomainAccess = KDefaultDomainAccess;
       
   375 
       
   376 #ifdef __SMP__
       
   377 	TInt i;
       
   378 	for (i=0; i<KMaxCpus; ++i)
       
   379 		{
       
   380 		TSubScheduler& ss = TheSubSchedulers[i];
       
   381 		TLinAddr a = KIPCAlias + (i<<KChunkShift);
       
   382 		ss.i_AliasLinAddr = (TAny*)a;
       
   383 		ss.i_AliasPdePtr = (TAny*)(KPageDirectoryBase + (a>>KChunkShift)*sizeof(TPde));
       
   384 		}
       
   385 #endif
       
   386 
       
   387 	Init1Common();
       
   388 	}
       
   389 
       
   390 void Mmu::Init2()
       
   391 	{
       
   392 	TRACEB(("Mmu::Init2"));
       
   393 
       
   394 	Init2Common();
       
   395 	}
       
   396 
       
   397 DMemoryObject* ExceptionStacks;
       
   398 
       
   399 void Mmu::Init2Final()
       
   400 	{
       
   401 	TRACEB(("Mmu::Init2Final"));
       
   402 
       
   403 	Init2FinalCommon();
       
   404 
       
   405 	// initialise memory object for exception stacks...
       
   406 	TMappingCreateFlags mapFlags = (TMappingCreateFlags)(EMappingCreateFixedVirtual|EMappingCreateReserveAllResources);
       
   407 	TMemoryAttributes memAttr = EMemoryAttributeStandard;
       
   408 	TUint size = 4*2*KPageSize; // 4 exception stacks each of one guard page and one mapped page
       
   409 	size |= 1; // lower bit of size is set if region to be claimed contains gaps
       
   410 	TInt r = MM::InitFixedKernelMemory(ExceptionStacks, KExcptStacksLinearBase, KExcptStacksLinearEnd, size, EMemoryObjectUnpaged, EMemoryCreateNoWipe, memAttr, mapFlags);
       
   411 	__NK_ASSERT_ALWAYS(r==KErrNone);
       
   412 	}
       
   413 
       
   414 
       
   415 /**
       
   416 Return the page directory entry (PDE) value to use for when mapping page tables intended
       
   417 to map memory with the given attributes.
       
   418 The returned value has the physical address component being zero, so a page table's physical
       
   419 address can be simply ORed in.
       
   420 */
       
   421 TPde Mmu::BlankPde(TMemoryAttributes aAttributes)
       
   422 	{
       
   423 	TPde pde = KArmV6PdePageTable;
       
   424 	if(aAttributes&EMemoryAttributeUseECC)
       
   425 		pde |= 1<<9;
       
   426 
       
   427 	TRACE2(("Mmu::BlankPde(%x) returns 0x%x",aAttributes,pde));
       
   428 	return pde;
       
   429 	}
       
   430 
       
   431 
       
   432 /**
       
   433 Return the page directory entry (PDE) value to use for when creating a section mapping for memory
       
   434 with the given attributes and #TPteType.
       
   435 The returned value has the physical address component being zero, so the section's physical address
       
   436 can be simply ORed in.
       
   437 */
       
   438 TPde Mmu::BlankSectionPde(TMemoryAttributes aAttributes, TUint aPteType)
       
   439 	{
       
   440 	// reuse existing functions rather than duplicating the logic
       
   441 	TPde pde = BlankPde(aAttributes);
       
   442 	TPde pte = BlankPte(aAttributes, aPteType);
       
   443 	return PageToSectionEntry(pte, pde);
       
   444 	}
       
   445 
       
   446 
       
   447 /**
       
   448 Return the page table entry (PTE) to use when mapping memory pages
       
   449 with the given attributes and #TPteType.
       
   450 This value has the physical address component being zero, so a page's physical
       
   451 address can be simply ORed in.
       
   452 */
       
   453 
       
   454 TPte Mmu::BlankPte(TMemoryAttributes aAttributes, TUint aPteType)
       
   455 	{
       
   456 	TUint attr = CanonicalMemoryAttributes(aAttributes);
       
   457 
       
   458 	// common PTE setup...
       
   459 	TPte pte = KArmV6PteSmallPage|KArmV6PteAP0;
       
   460 	if(aPteType&EPteTypeUserAccess)
       
   461 		pte |= KArmV6PteAP1;					// AP1 = user access
       
   462 	if((aPteType&EPteTypeWritable)==false)
       
   463 		pte |= KArmV6PteAP2;					// AP2 = !writable
       
   464 	if(attr&EMemoryAttributeShareable)
       
   465 		pte |= KArmV6PteS;
       
   466 	if((aPteType&EPteTypeGlobal)==false)
       
   467 		pte |= KArmV6PteNG;
       
   468 	if((aPteType&EPteTypeExecutable)==false)
       
   469 		pte |= KArmV6PteSmallXN;
       
   470 
       
   471 	#if defined(__CPU_MEMORY_TYPE_REMAPPING)
       
   472 
       
   473 		// other PTE bits...
       
   474 		if(pte&KArmV6PteSmallXN)
       
   475 			pte |= KArmV6PteSmallTEX1;	// TEX1 is a copy of the XN
       
   476 
       
   477 		// process memory type...
       
   478 		TUint type = attr&EMemoryAttributeTypeMask;
       
   479 		pte |= ((type&3)<<2) | ((type&4)<<4);
       
   480 
       
   481 	#else
       
   482 
       
   483 		// other PTE bits...
       
   484 		if((pte&(KArmV6PteAP2|KArmV6PteAP1))==(KArmV6PteAP2|KArmV6PteAP1))
       
   485 			pte &= ~KArmV6PteAP0;		// clear AP0 if user r/o
       
   486 
       
   487 		// process memory type...
       
   488 		TUint texcb;
       
   489 		switch((TMemoryType)(attr&EMemoryAttributeTypeMask))
       
   490 			{
       
   491 		case EMemAttStronglyOrdered:
       
   492 			texcb = KArmV6MemAttSO;
       
   493 			break;
       
   494 		case EMemAttDevice:
       
   495 			if(attr&EMemoryAttributeShareable)
       
   496 				texcb = KArmV6MemAttSD;
       
   497 			else
       
   498 				texcb = KArmV6MemAttSD;	// should be KArmV6MemAttNSD? (but this made H4 go bang)
       
   499 			break;
       
   500 		case EMemAttNormalUncached:
       
   501 			texcb = KArmV6MemAttNCNC;
       
   502 			break;
       
   503 		case EMemAttNormalCached:
       
   504 			texcb = KArmV6MemAttWBWAWBWA;
       
   505 			break;
       
   506 		default:
       
   507 			__NK_ASSERT_ALWAYS(0);		// undefined memory type
       
   508 			texcb = KArmV6MemAttSO;
       
   509 			break;
       
   510 			}
       
   511 		pte |= ((texcb&0x1c)<<4) | ((texcb&0x03)<<2);
       
   512 
       
   513 	#endif
       
   514 
       
   515 	TRACE2(("Mmu::BlankPte(%x,%x) returns 0x%x",aAttributes,aPteType,pte));
       
   516 	return pte;
       
   517 	}
       
   518 
       
   519 
       
   520 /**
       
   521 Calculate PDE and PTE which represent a page table mapping for an existing
       
   522 section mapping.
       
   523 
       
   524 @param[in] aPde The PDE for the existing section mapping.
       
   525 @param[out] aPde A PDE for a page table mapping, with physical address == 0.
       
   526 
       
   527 @return The PTE value for the first entry in the page table.
       
   528 */
       
   529 TPte Mmu::SectionToPageEntry(TPde& aPde)
       
   530 	{
       
   531 	TPde pde = aPde;
       
   532 
       
   533 	// calculate new PTE...
       
   534 	TPte pte = pde&0xc; // copy CB bits
       
   535 	if(pde&KArmV6PdeSectionXN)
       
   536 		pte |= KArmV6PteSmallXN; // copy XN bit
       
   537 	pte |= (pde&(0xff<<10))>>6; // copy NG, S, APX, TEX, AP bits
       
   538 	pte |= KArmV6PteSmallPage;
       
   539 
       
   540 	// calculate new PDE...
       
   541 	pde &= 0x3e0;	// keep IMP and DOMAIN
       
   542 	pde |= KArmV6PdePageTable;
       
   543 
       
   544 	aPde = pde;
       
   545 	return pte;
       
   546 	}
       
   547 
       
   548 
       
   549 /**
       
   550 Calculate a PDE entry which represents a section mapping for an existing
       
   551 page table mapping.
       
   552 
       
   553 @pre The existing page table contains mappings for a chunk sized and
       
   554 	 aligned contiguous region.
       
   555 
       
   556 @param aPte A PTE from the existing page table.
       
   557 @param aPde The existing PDE for the page table mappings.
       
   558 			(Physical address portion is ignored.)
       
   559 
       
   560 @return A PDE entry value for a section mapping.
       
   561 */
       
   562 TPde Mmu::PageToSectionEntry(TPte aPte, TPde aPde)
       
   563 	{
       
   564 	TPde pde = aPde&0x3e0;	// keep IMP and DOMAIN
       
   565 	pde |= aPte&(KPdeSectionAddrMask|0xc); // copy address and CB bits
       
   566 	if(aPte&KArmV6PteSmallXN)
       
   567 		pde |= KArmV6PdeSectionXN; // copy XN bit
       
   568 	pde |= (aPte&(0xff<<4))<<6;  // copy NG, S, APX, TEX, AP bits
       
   569 	pde |= KArmV6PdeSection;
       
   570 	return pde;
       
   571 	}
       
   572 
       
   573 
       
   574 /**
       
   575 Tranform the specified memory attributes into the canonical form relevant to
       
   576 the platform the code is running on. This applies defaults and overrides to
       
   577 the attributes to return what should be used with the MMU.
       
   578 */
       
   579 TMemoryAttributes Mmu::CanonicalMemoryAttributes(TMemoryAttributes aAttr)
       
   580 	{
       
   581 	TUint attr = aAttr;
       
   582 	if(attr&EMemoryAttributeDefaultShareable)
       
   583 		{
       
   584 		// sharing not specified, use default...
       
   585 #if defined	(__CPU_USE_SHARED_MEMORY)
       
   586 		attr |= EMemoryAttributeShareable;
       
   587 #else
       
   588 		attr &= ~EMemoryAttributeShareable;
       
   589 #endif
       
   590 		}
       
   591 
       
   592 #if defined(FAULTY_NONSHARED_DEVICE_MEMORY)
       
   593 	if((attr&(EMemoryAttributeShareable|EMemoryAttributeTypeMask))==EMemoryAttributeDevice)
       
   594 		{
       
   595 		// make unshared device memory into shared strongly ordered memory...
       
   596 		attr ^= EMemoryAttributeShareable;
       
   597 		attr ^= EMemoryAttributeDevice^EMemoryAttributeStronglyOrdered;
       
   598 		}
       
   599 #endif
       
   600 
       
   601 #if	defined(__SMP__) || defined(__CPU_FORCE_SHARED_MEMORY_IF_CACHED)
       
   602 	TMemoryType type = (TMemoryType)(attr&KMemoryTypeMask);
       
   603 	if(CacheMaintenance::IsCached(type))
       
   604 		{
       
   605 		// force cached memory to be shared memory on SMP systems...
       
   606 		attr |= EMemoryAttributeShareable;
       
   607 		}
       
   608 #endif
       
   609 
       
   610 	return (TMemoryAttributes)(attr&EMemoryAttributeMask);
       
   611 	}
       
   612 
       
   613 /**
       
   614 Method called to initialise RAM pages when they are allocated for a new use.
       
   615 This performs any cache synchronisation required to remove old entries
       
   616 and also wipes the contents of the memory (if requested via \a aFlags).
       
   617 
       
   618 @param aPageList	Pointer to a list of physical addresses for the RAM pages,
       
   619 					or, if the least significant bit of this value is set, then
       
   620 					the rest of the value is the physical address of a contiguous
       
   621 					region of RAM pages being allocated.
       
   622 
       
   623 @param aCount		The number of pages.
       
   624 
       
   625 @param aFlags		A set of flag values from #TRamAllocFlags which indicate
       
   626 					the memory type the pages will be used for and whether
       
   627 					the contents should be wiped.
       
   628 
       
   629 @param aReallocate	True, if the RAM pages have already been previously allocated
       
   630 					and are being reinitilised e.g. by DMemoryManager::ReAllocDecommitted.
       
   631 					False, to indicate that these pages have been newly allocated (are in
       
   632 					the SPageInfo::EUnused state.)
       
   633 
       
   634 @pre #RamAllocLock held.
       
   635 */
       
   636 void Mmu::PagesAllocated(TPhysAddr* aPageList, TUint aCount, TRamAllocFlags aFlags, TBool aReallocate)
       
   637 	{
       
   638 	TRACE2(("Mmu::PagesAllocated(0x%08x,%d,0x%x,%d)",aPageList, aCount, aFlags, (bool)aReallocate));
       
   639 	__NK_ASSERT_DEBUG(RamAllocLock::IsHeld());
       
   640 
       
   641 	TBool wipe = !(aFlags&EAllocNoWipe); // do we need to wipe page contents?
       
   642 	TUint8 wipeByte = (aFlags&EAllocUseCustomWipeByte) ? (aFlags>>EAllocWipeByteShift)&0xff : 0x03; // value to wipe memory with
       
   643 
       
   644 	// process each page in turn...
       
   645 	while(aCount--)
       
   646 		{
       
   647 		// get physical address of next page...
       
   648 		TPhysAddr pagePhys;
       
   649 		if((TPhysAddr)aPageList&1)
       
   650 			{
       
   651 			// aPageList is actually the physical address to use...
       
   652 			pagePhys = (TPhysAddr)aPageList&~1;
       
   653 			*(TPhysAddr*)&aPageList += KPageSize;
       
   654 			}
       
   655 		else
       
   656 			pagePhys = *aPageList++;
       
   657 		__NK_ASSERT_DEBUG((pagePhys&KPageMask)==0);
       
   658 
       
   659 		// get info about page...
       
   660 		SPageInfo* pi = SPageInfo::FromPhysAddr(pagePhys);
       
   661 		TMemoryType oldType = (TMemoryType)(pi->Flags(true)&KMemoryTypeMask);
       
   662 		TBool oldTypeNormal = CacheMaintenance::IsNormal(oldType);
       
   663 
       
   664 		TRACE2(("Mmu::PagesAllocated page=0x%08x, oldType=%d, wipe=%d, colour=%d",pagePhys,oldType,wipe,pi->Index(true)&KPageColourMask));
       
   665 		if(wipe || oldTypeNormal)
       
   666 			{
       
   667 			// work out temporary mapping values...
       
   668 			TUint colour = pi->Index(true)&KPageColourMask;
       
   669 			TLinAddr tempLinAddr = iTempMap[0].iLinAddr+colour*KPageSize;
       
   670 			TPte* tempPte = iTempMap[0].iPtePtr+colour;
       
   671 
       
   672 			if(oldTypeNormal)
       
   673 				{
       
   674 				// cache maintenance required. Prepare temporary mapping.
       
   675 				*tempPte = pagePhys | iTempPteCacheMaintenance;
       
   676 				CacheMaintenance::SinglePteUpdated((TLinAddr)tempPte);
       
   677 				InvalidateTLBForPage(tempLinAddr|KKernelOsAsid);
       
   678 
       
   679 				// will hold additional arguments in CacheMaintenance::PageToReuse call
       
   680 				TInt pageToReuseMask = 0;
       
   681 				
       
   682 				// check if old and new mappings are the same. (Wiping needs temporary
       
   683 				// mapping which may not be the same as the old and new mapping.)
       
   684 				TMemoryType newType = (TMemoryType)(aFlags&KMemoryTypeMask); // memory type that pages will be used for
       
   685 				if (!wipe && (newType ==oldType))
       
   686 					pageToReuseMask |= CacheMaintenance::EOldAndNewMappingMatch;
       
   687 
       
   688 				MmuLock::Lock();
       
   689 
       
   690 				// decide wether to trigger maintenance of entire cache(s).
       
   691 				if(CacheMaintenance::IsPageToReuseThresholdReached(iCacheInvalidatePageCount))
       
   692 					{
       
   693 					// enough pages to make it worth triggering maintenance of entire cache(s)
       
   694 					pageToReuseMask |= CacheMaintenance::EThresholdReached;
       
   695 					++iCacheInvalidateCounter;
       
   696 					iCacheInvalidatePageCount = 0; // all pages will be partially synced 
       
   697 					}
       
   698 				
       
   699 				if(CacheMaintenance::IsCached(oldType) && !aReallocate)
       
   700 					{
       
   701 					if(pi->CacheInvalidateCounter()==(TUint32)iCacheInvalidateCounter)
       
   702 						{
       
   703 						// one less unused page in the L1 cache...
       
   704 						__NK_ASSERT_DEBUG(iCacheInvalidatePageCount);
       
   705 						--iCacheInvalidatePageCount;
       
   706 						}
       
   707 					else
       
   708 						{
       
   709 						// our page has been already partially maintained in cache
       
   710 						// by a previous PageToReuse call.
       
   711 						pageToReuseMask |= CacheMaintenance::EPageHasBeenPartiallySynced;
       
   712 						}
       
   713 					}
       
   714 				
       
   715 				MmuLock::Unlock();
       
   716 				
       
   717 				TBool pageRemovedFromCache = CacheMaintenance::PageToReuse(tempLinAddr, oldType, pagePhys, pageToReuseMask);
       
   718 				if(pageRemovedFromCache && !aReallocate)
       
   719 					pi->SetUncached();
       
   720 				}
       
   721 
       
   722 			if(wipe)
       
   723 				{
       
   724 				//We need uncached normal temporary mapping to wipe. Change it if necessary.
       
   725 				//or , in case of !oldTypeNormal it is not configured yet.
       
   726 				if (!oldTypeNormal || (CacheMaintenance::TemporaryMapping()!=EMemAttNormalUncached))
       
   727 					{
       
   728 					*tempPte = pagePhys | iTempPteUncached;
       
   729 					CacheMaintenance::SinglePteUpdated((TLinAddr)tempPte);
       
   730 					InvalidateTLBForPage(tempLinAddr|KKernelOsAsid);
       
   731 					}
       
   732 				// wipe contents of memory...
       
   733 				memset((TAny*)tempLinAddr, wipeByte, KPageSize);
       
   734 				CacheMaintenance::PageToReuse(tempLinAddr, EMemAttNormalUncached, pagePhys);
       
   735 				}
       
   736 
       
   737 			// invalidate temporary mapping...
       
   738 			*tempPte = KPteUnallocatedEntry;
       
   739 			CacheMaintenance::SinglePteUpdated((TLinAddr)tempPte);
       
   740 			InvalidateTLBForPage(tempLinAddr|KKernelOsAsid);
       
   741 			}
       
   742 
       
   743 		// indicate page has been allocated...
       
   744 		if(!aReallocate)
       
   745 			pi->SetAllocated();
       
   746 
       
   747 		// loop round for next page...
       
   748 		} // end of while(aCount--)
       
   749 	}
       
   750 
       
   751 
       
   752 /**
       
   753 Method called to update the state of a RAM page when it is freed.
       
   754 This sets the page state to SPageInfo::EUnused.
       
   755 
       
   756 @param aPageInfo	The page information structure for the RAM page.
       
   757 
       
   758 @pre #MmuLock held.
       
   759 */
       
   760 void Mmu::PageFreed(SPageInfo* aPageInfo)
       
   761 	{
       
   762 	__NK_ASSERT_DEBUG(MmuLock::IsHeld());
       
   763 
       
   764 	if(aPageInfo->Type()==SPageInfo::EUnused)
       
   765 		return;
       
   766 
       
   767 	aPageInfo->SetUnused();
       
   768 
       
   769 	TMemoryType type = (TMemoryType)(aPageInfo->Flags()&KMemoryTypeMask);
       
   770 	if(CacheMaintenance::IsCached(type))
       
   771 		{
       
   772 		// another unused page with L1 cache entries...
       
   773 		aPageInfo->SetCacheInvalidateCounter(iCacheInvalidateCounter);
       
   774 		++iCacheInvalidatePageCount;
       
   775 		}
       
   776 
       
   777 	TRACE2(("Mmu::PageFreed page=0x%08x type=%d colour=%d",aPageInfo->PhysAddr(),aPageInfo->Flags()&KMemoryTypeMask,aPageInfo->Index()&KPageColourMask));
       
   778 	}
       
   779 
       
   780 /**
       
   781 Remove the contents of RAM pages from any memory caches.
       
   782 
       
   783 @param aPages		Pointer to a list of physical addresses for the RAM pages,
       
   784 					or, if the least significant bit of this value is set, then
       
   785 					the rest of the value is the physical address of a contiguous
       
   786 					region of RAM pages.
       
   787 
       
   788 @param aCount		The number of pages.
       
   789 
       
   790 @param aAttributes	The memory attributes of the pages.
       
   791 
       
   792 @param aColour 		The colour for the first page;
       
   793 					consecutive pages will be coloured accordingly.
       
   794 					Only #KPageColourShift least significant bits are used,
       
   795 					therefore an index into a memory object's memory can be
       
   796 					used for this value.
       
   797 */
       
   798 void Mmu::CleanAndInvalidatePages(TPhysAddr* aPages, TUint aCount, TMemoryAttributes aAttributes, TUint aColour)
       
   799 	{
       
   800 	TMemoryType type = (TMemoryType)(aAttributes&EMemoryAttributeTypeMask);
       
   801 
       
   802 	if(!CacheMaintenance::IsNormal(type))
       
   803 		{
       
   804 		TRACE2(("Mmu::CleanAndInvalidatePages - nothing to do"));
       
   805 		return;
       
   806 		}
       
   807 	
       
   808 	RamAllocLock::Lock();
       
   809 
       
   810 	while(aCount--)
       
   811 		{
       
   812 		TPhysAddr pagePhys = *aPages++;
       
   813 		TRACE2(("Mmu::CleanAndInvalidatePages 0x%08x",pagePhys));
       
   814 
       
   815 		// work out temporary mapping values...
       
   816 		aColour &= KPageColourMask;
       
   817 		TLinAddr tempLinAddr = iTempMap[0].iLinAddr+aColour*KPageSize;
       
   818 		TPte* tempPte = iTempMap[0].iPtePtr+aColour;
       
   819 		++aColour;
       
   820 
       
   821 		// temporarily map page...
       
   822 		*tempPte = pagePhys | iTempPteCacheMaintenance;
       
   823 		CacheMaintenance::SinglePteUpdated((TLinAddr)tempPte);
       
   824 		InvalidateTLBForPage(tempLinAddr|KKernelOsAsid);
       
   825 
       
   826 		// preserve memory content and remove from cache...
       
   827 		CacheMaintenance::PageToPreserveAndReuse(tempLinAddr, type, pagePhys);
       
   828 
       
   829 		// invalidate temporary mapping...
       
   830 		*tempPte = KPteUnallocatedEntry;
       
   831 		CacheMaintenance::SinglePteUpdated((TLinAddr)tempPte);
       
   832 		InvalidateTLBForPage(tempLinAddr|KKernelOsAsid);
       
   833 
       
   834 		RamAllocLock::Flash();
       
   835 		}
       
   836 	RamAllocLock::Unlock();
       
   837 	}
       
   838 
       
   839 
       
   840 extern void UnlockIPCAlias();
       
   841 extern void LockIPCAlias();
       
   842 
       
   843 
       
   844 TInt DMemModelThread::Alias(TLinAddr aAddr, DMemModelProcess* aProcess, TInt aSize, TLinAddr& aAliasAddr, TUint& aAliasSize)
       
   845 //
       
   846 // Set up an alias mapping starting at address aAddr in specified process.
       
   847 // Note: Alias is removed if an exception is trapped by DThread::IpcExcHandler.
       
   848 //
       
   849 	{
       
   850 	TRACE2(("Thread %O Alias %08x+%x Process %O",this,aAddr,aSize,aProcess));
       
   851 	__NK_ASSERT_DEBUG(this==TheCurrentThread); // many bad things can happen if false
       
   852 	// If there is an existing alias it should be on the same process otherwise
       
   853 	// the os asid reference may be leaked.
       
   854 	__NK_ASSERT_DEBUG(!iAliasLinAddr || aProcess == iAliasProcess);
       
   855 
       
   856 	if(TUint(aAddr^KIPCAlias)<TUint(KIPCAliasAreaSize))
       
   857 		return KErrBadDescriptor; // prevent access to alias region
       
   858 
       
   859 	// Grab the mmu lock before opening a reference on os asid so that this thread 
       
   860 	// is in an implicit critical section and therefore can't leak the reference by
       
   861 	// dying before iAliasLinAddr is set.
       
   862 	MmuLock::Lock();
       
   863 
       
   864 	TInt osAsid;
       
   865 	if (!iAliasLinAddr)
       
   866 		{// There isn't any existing alias.
       
   867 		// Open a reference on the aProcess's os asid so that it is not freed and/or reused
       
   868 		// while we are aliasing an address belonging to it.
       
   869 		osAsid = aProcess->TryOpenOsAsid();
       
   870 		if (osAsid < 0)
       
   871 			{// Couldn't open os asid so aProcess is no longer running.
       
   872 			MmuLock::Unlock();
       
   873 			return KErrBadDescriptor;
       
   874 			}
       
   875 		}
       
   876 	else
       
   877 		{
       
   878 		// Just read the os asid of the process being aliased we already have a reference on it.
       
   879 		osAsid = aProcess->OsAsid();
       
   880 		}
       
   881 
       
   882 	// Now we have the os asid check access to kernel memory.
       
   883 	if(aAddr >= KUserMemoryLimit && osAsid != (TUint)KKernelOsAsid)
       
   884 		{
       
   885 		if (!iAliasLinAddr)
       
   886 			{// Close the new reference as RemoveAlias won't do as iAliasLinAddr is not set.
       
   887 			aProcess->AsyncCloseOsAsid();
       
   888 			}
       
   889 		MmuLock::Unlock();
       
   890 		return KErrBadDescriptor; // prevent access to supervisor only memory
       
   891 		}
       
   892 
       
   893 	// Now we know all accesses to global memory are safe so check if aAddr is global.
       
   894 	if(aAddr >= KGlobalMemoryBase)
       
   895 		{
       
   896 		// address is in global section, don't bother aliasing it...
       
   897 		if (!iAliasLinAddr)
       
   898 			{// Close the new reference as not required.
       
   899 			aProcess->AsyncCloseOsAsid();
       
   900 			}
       
   901 		else
       
   902 			{// Remove the existing alias as it is not required.
       
   903 			DoRemoveAlias(iAliasLinAddr);
       
   904 			}
       
   905 		MmuLock::Unlock();
       
   906 		aAliasAddr = aAddr;
       
   907 		TInt maxSize = KChunkSize-(aAddr&KChunkMask);
       
   908 		aAliasSize = aSize<maxSize ? aSize : maxSize;
       
   909 		TRACE2(("DMemModelThread::Alias() abandoned as memory is globally mapped"));
       
   910 		return KErrNone;
       
   911 		}
       
   912 
       
   913 	TPde* pd = Mmu::PageDirectory(osAsid);
       
   914 	TInt pdeIndex = aAddr>>KChunkShift;
       
   915 	TPde pde = pd[pdeIndex];
       
   916 	pde = (pde&~(0xf<<5))|(KIPCAliasDomain<<5); // change domain for PDE
       
   917 	// Get os asid, this is the current thread's process so no need for reference.
       
   918 	TUint32 local_asid = ((DMemModelProcess*)iOwningProcess)->OsAsid();
       
   919 #ifdef __SMP__
       
   920 	TLinAddr aliasAddr;
       
   921 #else
       
   922 	TLinAddr aliasAddr = KIPCAlias+(aAddr&(KChunkMask & ~KPageMask));
       
   923 #endif
       
   924 	if(pde==iAliasPde && iAliasLinAddr)
       
   925 		{
       
   926 		// pde already aliased, so just update linear address...
       
   927 #ifdef __SMP__
       
   928 		__NK_ASSERT_DEBUG(iCpuRestoreCookie>=0);
       
   929 		aliasAddr = iAliasLinAddr & ~KChunkMask;
       
   930 		aliasAddr |= (aAddr & (KChunkMask & ~KPageMask));
       
   931 #endif
       
   932 		iAliasLinAddr = aliasAddr;
       
   933 		}
       
   934 	else
       
   935 		{
       
   936 		// alias PDE changed...
       
   937 		if(!iAliasLinAddr)
       
   938 			{
       
   939 			UnlockIPCAlias();
       
   940 			TheMmu.iAliasList.Add(&iAliasLink); // add to list if not already aliased
       
   941 #ifdef __SMP__
       
   942 			__NK_ASSERT_DEBUG(iCpuRestoreCookie==-1);
       
   943 			iCpuRestoreCookie = NKern::FreezeCpu();	// temporarily lock current thread to this processor
       
   944 #endif
       
   945 			}
       
   946 		iAliasPde = pde;
       
   947 		iAliasProcess = aProcess;
       
   948 #ifdef __SMP__
       
   949 		TSubScheduler& ss = SubScheduler();		// OK since we are locked to this CPU
       
   950 		aliasAddr = TLinAddr(ss.i_AliasLinAddr) + (aAddr & (KChunkMask & ~KPageMask));
       
   951 		iAliasPdePtr = (TPde*)(TLinAddr(ss.i_AliasPdePtr) + (local_asid << KPageDirectoryShift));
       
   952 #endif
       
   953 		iAliasLinAddr = aliasAddr;
       
   954 		*iAliasPdePtr = pde;
       
   955 		SinglePdeUpdated(iAliasPdePtr);
       
   956 		}
       
   957 
       
   958 	TRACE2(("DMemModelThread::Alias() PDEntry=%x, iAliasLinAddr=%x",pde, aliasAddr));
       
   959 	LocalInvalidateTLBForPage(aliasAddr | local_asid);
       
   960 	TInt offset = aAddr&KPageMask;
       
   961 	aAliasAddr = aliasAddr | offset;
       
   962 	TInt maxSize = KPageSize - offset;
       
   963 	aAliasSize = aSize<maxSize ? aSize : maxSize;
       
   964 	iAliasTarget = aAddr & ~KPageMask;
       
   965 
       
   966 	MmuLock::Unlock();
       
   967 
       
   968 	return KErrNone;
       
   969 	}
       
   970 
       
   971 
       
   972 void DMemModelThread::RemoveAlias()
       
   973 //
       
   974 // Remove alias mapping (if present)
       
   975 //
       
   976 	{
       
   977 	TRACE2(("Thread %O RemoveAlias", this));
       
   978 	__NK_ASSERT_DEBUG(this==TheCurrentThread); // many bad things can happen if false
       
   979 
       
   980 	TLinAddr addr = iAliasLinAddr;
       
   981 	if(addr)
       
   982 		{
       
   983 		MmuLock::Lock();
       
   984 
       
   985 		DoRemoveAlias(addr);
       
   986 
       
   987 		MmuLock::Unlock();
       
   988 		}
       
   989 	}
       
   990 
       
   991 
       
   992 /**
       
   993 Remove the alias mapping.
       
   994 
       
   995 @pre Mmulock held
       
   996 */
       
   997 void DMemModelThread::DoRemoveAlias(TLinAddr aAddr)
       
   998 	{
       
   999 	LockIPCAlias();
       
  1000 	iAliasLinAddr = 0;
       
  1001 	iAliasPde = KPdeUnallocatedEntry;
       
  1002 	*iAliasPdePtr = KPdeUnallocatedEntry;
       
  1003 	SinglePdeUpdated(iAliasPdePtr);
       
  1004 	__NK_ASSERT_DEBUG((aAddr&KPageMask)==0);
       
  1005 	// Invalidate the tlb using os asid, no need to open a reference as this
       
  1006 	// is the current thread's process os asid.
       
  1007 	LocalInvalidateTLBForPage(aAddr | ((DMemModelProcess*)iOwningProcess)->OsAsid());
       
  1008 	iAliasLink.Deque();
       
  1009 #ifdef __SMP__
       
  1010 	__NK_ASSERT_DEBUG(iCpuRestoreCookie>=0);
       
  1011 	NKern::EndFreezeCpu(iCpuRestoreCookie);
       
  1012 	iCpuRestoreCookie = -1;
       
  1013 #endif
       
  1014 	// Must close the os asid while the mmu lock is held to prevent it being 
       
  1015 	// leaked, however this requires that it is closed asynchronously as can't
       
  1016 	// delete os asid with mmu lock held.
       
  1017 	iAliasProcess->AsyncCloseOsAsid();
       
  1018 	}
       
  1019 
       
  1020 
       
  1021 TInt M::DemandPagingFault(TAny* aExceptionInfo)
       
  1022 	{
       
  1023 	TArmExcInfo& exc=*(TArmExcInfo*)aExceptionInfo;
       
  1024 
       
  1025 	// permissions required by faulting memory access...
       
  1026 	TUint accessPermissions = EUser; // we only allow paging of user memory
       
  1027 
       
  1028 	// get faulting address...
       
  1029 	TLinAddr faultAddress = exc.iFaultAddress;
       
  1030 	if(exc.iExcCode==EArmExceptionPrefetchAbort)
       
  1031 		{
       
  1032 		// fault trying to read code to execute...
       
  1033 		accessPermissions |= EExecute;
       
  1034 		}
       
  1035 	else if(exc.iExcCode!=EArmExceptionDataAbort)
       
  1036 		return KErrUnknown; // not prefetch or data abort
       
  1037 
       
  1038 	// check fault type...
       
  1039 	if((exc.iFaultStatus&0x405) != 5 && (exc.iFaultStatus&0x40f) != 4)
       
  1040 		return KErrUnknown; // not translation, permission or instruction cache maintenance fault.
       
  1041 
       
  1042 	// check access type...
       
  1043 	if(exc.iFaultStatus&(1<<11))
       
  1044 		accessPermissions |= EReadWrite;
       
  1045 
       
  1046 	// let TheMmu handle the fault...
       
  1047 	return TheMmu.HandlePageFault(exc.iR15, faultAddress, accessPermissions, aExceptionInfo);
       
  1048 	}
       
  1049 
       
  1050