--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/memmodel/epoc/flexible/mmu/x86/xmmu.cpp Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,732 @@
+// 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:
+//
+
+#include <x86_mem.h>
+#include "cache_maintenance.inl"
+#include "execs.h"
+#include "mm.h"
+#include "mmu.h"
+#include "mpager.h"
+#include "mpdalloc.h"
+
+
+TPte PteGlobal; // =0x100 on processors which support global pages, 0 on processors which don't
+
+#if defined(KMMU)
+extern "C" void __DebugMsgFlushTLB()
+ {
+ __KTRACE_OPT(KMMU,Kern::Printf("FlushTLB"));
+ }
+
+extern "C" void __DebugMsgLocalFlushTLB()
+ {
+ __KTRACE_OPT(KMMU,Kern::Printf("FlushTLB"));
+ }
+
+extern "C" void __DebugMsgINVLPG(int a)
+ {
+ __KTRACE_OPT(KMMU,Kern::Printf("INVLPG(%08x)",a));
+ }
+#endif
+
+
+
+extern void DoLocalInvalidateTLB();
+
+
+#ifndef __SMP__
+
+
+FORCE_INLINE void LocalInvalidateTLB()
+ {
+ DoLocalInvalidateTLB();
+ }
+
+
+#else // __SMP__
+
+
+const TInt KMaxPages = 1;
+
+class TTLBIPI : public TGenericIPI
+ {
+public:
+ TTLBIPI();
+ static void InvalidateForPagesIsr(TGenericIPI*);
+ static void LocalInvalidateIsr(TGenericIPI*);
+ static void InvalidateIsr(TGenericIPI*);
+ static void WaitAndInvalidateIsr(TGenericIPI*);
+ void AddAddress(TLinAddr aAddr);
+ void InvalidateList();
+public:
+ volatile TInt iFlag;
+ TInt iCount;
+ TLinAddr iAddr[KMaxPages];
+ };
+
+TTLBIPI::TTLBIPI()
+ : iFlag(0), iCount(0)
+ {
+ }
+
+void TTLBIPI::LocalInvalidateIsr(TGenericIPI*)
+ {
+ TRACE2(("TLBLocInv"));
+ DoLocalInvalidateTLB();
+ }
+
+void TTLBIPI::InvalidateIsr(TGenericIPI*)
+ {
+ TRACE2(("TLBInv"));
+ DoInvalidateTLB();
+ }
+
+void TTLBIPI::WaitAndInvalidateIsr(TGenericIPI* aTLBIPI)
+ {
+ TRACE2(("TLBWtInv"));
+ TTLBIPI& a = *(TTLBIPI*)aTLBIPI;
+ while (!a.iFlag)
+ {}
+ if (a.iCount == 1)
+ DoInvalidateTLBForPage(a.iAddr[0]);
+ else
+ DoInvalidateTLB();
+ }
+
+void TTLBIPI::InvalidateForPagesIsr(TGenericIPI* aTLBIPI)
+ {
+ TTLBIPI& a = *(TTLBIPI*)aTLBIPI;
+ TInt i;
+ for (i=0; i<a.iCount; ++i)
+ {
+ TRACE2(("TLBInv %08x", a.iAddr[i]));
+ DoInvalidateTLBForPage(a.iAddr[i]);
+ }
+ }
+
+void TTLBIPI::AddAddress(TLinAddr aAddr)
+ {
+ iAddr[iCount] = aAddr;
+ if (++iCount == KMaxPages)
+ InvalidateList();
+ }
+
+void TTLBIPI::InvalidateList()
+ {
+ NKern::Lock();
+ InvalidateForPagesIsr(this);
+ QueueAllOther(&InvalidateForPagesIsr);
+ NKern::Unlock();
+ WaitCompletion();
+ iCount = 0;
+ }
+
+void LocalInvalidateTLB()
+ {
+ TTLBIPI ipi;
+ NKern::Lock();
+ DoLocalInvalidateTLB();
+ ipi.QueueAllOther(&TTLBIPI::LocalInvalidateIsr);
+ NKern::Unlock();
+ ipi.WaitCompletion();
+ }
+
+void InvalidateTLB()
+ {
+ TTLBIPI ipi;
+ NKern::Lock();
+ DoInvalidateTLB();
+ ipi.QueueAllOther(&TTLBIPI::InvalidateIsr);
+ NKern::Unlock();
+ ipi.WaitCompletion();
+ }
+
+void InvalidateTLBForPage(TLinAddr aAddr)
+ {
+ TTLBIPI ipi;
+ ipi.AddAddress(aAddr);
+ ipi.InvalidateList();
+ }
+
+
+#endif // __SMP__
+
+
+void InvalidateTLBForAsid(TUint aAsid)
+ {
+ if(aAsid==KKernelOsAsid)
+ InvalidateTLB();
+ else
+ LocalInvalidateTLB();
+ }
+
+
+void SinglePdeUpdated(TPde* aPde)
+ {
+ CacheMaintenance::SinglePdeUpdated((TLinAddr)aPde);
+ PageDirectories.GlobalPdeChanged(aPde);
+ }
+
+
+//
+// Functions for class Mmu
+//
+
+TPhysAddr Mmu::PtePhysAddr(TPte aPte, TUint /*aPteIndex*/)
+ {
+ if(aPte&KPdePtePresent)
+ return aPte & KPdePtePhysAddrMask;
+ return KPhysAddrInvalid;
+ }
+
+
+TPte* Mmu::PageTableFromPde(TPde aPde)
+ {
+ if((aPde&(KPdeLargePage|KPdePtePresent)) == KPdePtePresent)
+ {
+ SPageInfo* pi = SPageInfo::FromPhysAddr(aPde);
+ TInt id = (pi->Index()<<KPtClusterShift) | ((aPde>>KPageTableShift)&KPtClusterMask);
+ return (TPte*)(KPageTableBase+(id<<KPageTableShift));
+ }
+ return 0;
+ }
+
+
+TPte* Mmu::SafePageTableFromPde(TPde aPde)
+ {
+ if((aPde&(KPdeLargePage|KPdePtePresent)) == KPdePtePresent)
+ {
+ SPageInfo* pi = SPageInfo::SafeFromPhysAddr(aPde&~KPageMask);
+ if(pi)
+ {
+ TInt id = (pi->Index()<<KPtClusterShift) | ((aPde>>KPageTableShift)&KPtClusterMask);
+ return (TPte*)(KPageTableBase+(id<<KPageTableShift));
+ }
+ }
+ return 0;
+ }
+
+
+/**
+Return the base phsical address of the section table referenced by the given
+Page Directory Entry (PDE) \a aPde. If the PDE doesn't refer to a
+section then KPhysAddrInvalid is returned.
+
+@pre #MmuLock held.
+*/
+TPhysAddr Mmu::SectionBaseFromPde(TPde aPde)
+ {
+ if(PdeMapsSection(aPde))
+ return aPde&KPdeLargePagePhysAddrMask;
+ return KPhysAddrInvalid;
+ }
+
+
+TPte* Mmu::PtePtrFromLinAddr(TLinAddr aAddress, TInt aOsAsid)
+ {
+ TPde pde = PageDirectory(aOsAsid)[aAddress>>KChunkShift];
+ SPageInfo* pi = SPageInfo::FromPhysAddr(pde);
+ TPte* pt = (TPte*)(KPageTableBase+(pi->Index()<<KPageShift)+(pde&(KPageMask&~KPageTableMask)));
+ pt += (aAddress>>KPageShift)&(KChunkMask>>KPageShift);
+ return pt;
+ }
+
+
+TPte* Mmu::SafePtePtrFromLinAddr(TLinAddr aAddress, TInt aOsAsid)
+ {
+ TPde pde = PageDirectory(aOsAsid)[aAddress>>KChunkShift];
+ TPte* pt = SafePageTableFromPde(pde);
+ if(pt)
+ pt += (aAddress>>KPageShift)&(KChunkMask>>KPageShift);
+ return pt;
+ }
+
+
+TPhysAddr Mmu::PageTablePhysAddr(TPte* aPt)
+ {
+ __NK_ASSERT_DEBUG(MmuLock::IsHeld() || PageTablesLockIsHeld());
+
+ TInt pdeIndex = ((TLinAddr)aPt)>>KChunkShift;
+ TPde pde = PageDirectory(KKernelOsAsid)[pdeIndex];
+ __NK_ASSERT_DEBUG((pde&(KPdePtePresent|KPdeLargePage))==KPdePtePresent);
+
+ SPageInfo* pi = SPageInfo::FromPhysAddr(pde);
+ TPte* pPte = (TPte*)(KPageTableBase+(pi->Index(true)<<KPageShift));
+ TPte pte = pPte[(((TLinAddr)aPt)&KChunkMask)>>KPageShift];
+ __NK_ASSERT_DEBUG(pte & KPdePtePresent);
+
+ return pte&KPdePtePhysAddrMask;
+ }
+
+
+TPhysAddr Mmu::UncheckedLinearToPhysical(TLinAddr aLinAddr, TInt aOsAsid)
+ {
+ TRACE2(("Mmu::UncheckedLinearToPhysical(%08x,%d)",aLinAddr,aOsAsid));
+ TInt pdeIndex = aLinAddr>>KChunkShift;
+ TPde pde = PageDirectory(aOsAsid)[pdeIndex];
+ TPhysAddr pa=KPhysAddrInvalid;
+ if (pde & KPdePtePresent)
+ {
+ if(pde&KPdeLargePage)
+ {
+ pa=(pde&KPdeLargePagePhysAddrMask)+(aLinAddr&~KPdeLargePagePhysAddrMask);
+ __KTRACE_OPT(KMMU,Kern::Printf("Mapped with large table - returning %08x",pa));
+ }
+ else
+ {
+ SPageInfo* pi = SPageInfo::FromPhysAddr(pde);
+ TInt id = (pi->Index(true)<<KPtClusterShift) | ((pde>>KPageTableShift)&KPtClusterMask);
+ TPte* pPte = (TPte*)(KPageTableBase+(id<<KPageTableShift));
+ TPte pte = pPte[(aLinAddr&KChunkMask)>>KPageShift];
+ if (pte & KPdePtePresent)
+ {
+ pa=(pte&KPdePtePhysAddrMask)+(aLinAddr&KPageMask);
+ __KTRACE_OPT(KMMU,Kern::Printf("Mapped with page table - returning %08x",pa));
+ }
+ }
+ }
+ return pa;
+ }
+
+
+void Mmu::Init1()
+ {
+ TRACEB(("Mmu::Init1"));
+
+ TUint pge = TheSuperPage().iCpuId & EX86Feat_PGE;
+ PteGlobal = pge ? KPdePteGlobal : 0;
+ X86_UseGlobalPTEs = pge!=0;
+
+#ifdef __SMP__
+ ApTrampolinePage = KApTrampolinePageLin;
+
+ TInt i;
+ for (i=0; i<KMaxCpus; ++i)
+ {
+ TSubScheduler& ss = TheSubSchedulers[i];
+ TLinAddr a = KIPCAlias + (i<<KChunkShift);
+ ss.i_AliasLinAddr = (TAny*)a;
+ ss.i_AliasPdePtr = (TAny*)(KPageDirectoryBase + (a>>KChunkShift)*sizeof(TPde));
+ }
+#endif
+
+ Init1Common();
+ }
+
+void Mmu::Init2()
+ {
+ TRACEB(("Mmu::Init2"));
+
+ Init2Common();
+ }
+
+void Mmu::Init2Final()
+ {
+ TRACEB(("Mmu::Init2Final"));
+
+ Init2FinalCommon();
+ }
+
+
+const TPde KPdeForBlankPageTable = KPdePtePresent|KPdePteWrite|KPdePteUser;
+
+TPde Mmu::BlankPde(TMemoryAttributes aAttributes)
+ {
+ (void)aAttributes;
+ TPde pde = KPdeForBlankPageTable;
+ TRACE2(("Mmu::BlankPde(%x) returns 0x%x",aAttributes,pde));
+ return pde;
+ }
+
+
+TPde Mmu::BlankSectionPde(TMemoryAttributes aAttributes, TUint aPteType)
+ {
+ return PageToSectionEntry(BlankPte(aAttributes, aPteType), KPdeForBlankPageTable);
+ }
+
+
+TPte Mmu::BlankPte(TMemoryAttributes aAttributes, TUint aPteType)
+ {
+ TPte pte = KPdePtePresent;
+ if(aPteType&EPteTypeUserAccess)
+ pte |= KPdePteUser;
+ if(aPteType&EPteTypeWritable)
+ pte |= KPdePteWrite;
+ if(aPteType&EPteTypeGlobal)
+ pte |= PteGlobal;
+
+ switch((TMemoryType)(aAttributes&EMemoryAttributeTypeMask))
+ {
+ case EMemAttStronglyOrdered:
+ case EMemAttDevice:
+ case EMemAttNormalUncached:
+ pte |= KPdePteUncached;
+ break;
+ case EMemAttNormalCached:
+ break;
+ default:
+ __NK_ASSERT_ALWAYS(0);
+ break;
+ }
+
+ TRACE2(("Mmu::BlankPte(%x,%x) returns 0x%x",aAttributes,aPteType,pte));
+ return pte;
+ }
+
+
+TPte Mmu::SectionToPageEntry(TPde& aPde)
+ {
+ TPte pte = aPde&~(KPdePtePhysAddrMask|KPdeLargePage);
+ aPde = KPdeForBlankPageTable;
+ return pte;
+ }
+
+
+TPde Mmu::PageToSectionEntry(TPte aPte, TPde /*aPde*/)
+ {
+ TPte pde = aPte&~KPdeLargePagePhysAddrMask;
+ pde |= KPdeLargePage;
+ return pde;
+ }
+
+
+TMemoryAttributes Mmu::CanonicalMemoryAttributes(TMemoryAttributes aAttr)
+ {
+ TUint attr = aAttr;
+ if(attr&EMemoryAttributeDefaultShareable)
+ {
+ // sharing not specified, use default...
+#if defined (__CPU_USE_SHARED_MEMORY)
+ attr |= EMemoryAttributeShareable;
+#else
+ attr &= ~EMemoryAttributeShareable;
+#endif
+ }
+
+ // remove invalid attributes...
+ attr &= ~(EMemoryAttributeUseECC);
+
+ return (TMemoryAttributes)(attr&EMemoryAttributeMask);
+ }
+
+
+void Mmu::PagesAllocated(TPhysAddr* aPageList, TUint aCount, TRamAllocFlags aFlags, TBool aReallocate)
+ {
+ TRACE2(("Mmu::PagesAllocated(0x%08x,%d,0x%x,%d)",aPageList, aCount, aFlags, (bool)aReallocate));
+ __NK_ASSERT_DEBUG(RamAllocLock::IsHeld());
+
+ TBool wipe = !(aFlags&EAllocNoWipe); // do we need to wipe page contents?
+ TMemoryType newType = (TMemoryType)(aFlags&KMemoryTypeMask); // memory type that pages will be used for
+ TUint8 wipeByte = (aFlags&EAllocUseCustomWipeByte) ? (aFlags>>EAllocWipeByteShift)&0xff : 0x03; // value to wipe memory with
+
+ // process each page in turn...
+ while(aCount--)
+ {
+ // get physical address of next page...
+ TPhysAddr pagePhys;
+ if((TPhysAddr)aPageList&1)
+ {
+ // aPageList is actually the physical address to use...
+ pagePhys = (TPhysAddr)aPageList&~1;
+ *(TPhysAddr*)&aPageList += KPageSize;
+ }
+ else
+ pagePhys = *aPageList++;
+ __NK_ASSERT_DEBUG((pagePhys&KPageMask)==0);
+
+ // get info about page...
+ SPageInfo* pi = SPageInfo::FromPhysAddr(pagePhys);
+ TMemoryType oldType = (TMemoryType)(pi->Flags(true)&KMemoryTypeMask);
+
+ TRACE2(("Mmu::PagesAllocated page=0x%08x, oldType=%d, wipe=%d",pagePhys,oldType,wipe));
+ if(wipe)
+ {
+ // work out temporary mapping values...
+ TLinAddr tempLinAddr = iTempMap[0].iLinAddr;
+ TPte* tempPte = iTempMap[0].iPtePtr;
+
+ // temporarily map page...
+ *tempPte = pagePhys | iTempPteCached;
+ CacheMaintenance::SinglePteUpdated((TLinAddr)tempPte);
+ InvalidateTLBForPage(tempLinAddr|KKernelOsAsid);
+
+ // wipe contents of memory...
+ memset((TAny*)tempLinAddr, wipeByte, KPageSize);
+ __e32_io_completion_barrier();
+
+ // invalidate temporary mapping...
+ *tempPte = KPteUnallocatedEntry;
+ CacheMaintenance::SinglePteUpdated((TLinAddr)tempPte);
+ InvalidateTLBForPage(tempLinAddr|KKernelOsAsid);
+ }
+
+ // indicate page has been allocated...
+ if(aReallocate==false)
+ pi->SetAllocated();
+ }
+ }
+
+
+void Mmu::PageFreed(SPageInfo* aPageInfo)
+ {
+ __NK_ASSERT_DEBUG(MmuLock::IsHeld());
+
+ if(aPageInfo->Type()==SPageInfo::EUnused)
+ return;
+
+ aPageInfo->SetUnused();
+
+ TRACE2(("Mmu::PageFreed page=0x%08x type=%d colour=%d",aPageInfo->PhysAddr(),aPageInfo->Flags()&KMemoryTypeMask,aPageInfo->Index()&KPageColourMask));
+ }
+
+
+void Mmu::CleanAndInvalidatePages(TPhysAddr* aPages, TUint aCount, TMemoryAttributes aAttributes, TUint aColour)
+ {
+ TMemoryType type = (TMemoryType)(aAttributes&EMemoryAttributeTypeMask);
+ if(!CacheMaintenance::IsCached(type))
+ {
+ TRACE2(("Mmu::CleanAndInvalidatePages - nothing to do"));
+ return;
+ }
+
+ RamAllocLock::Lock();
+
+ while(aCount--)
+ {
+ TPhysAddr pagePhys = *aPages++;
+ TRACE2(("Mmu::CleanAndInvalidatePages 0x%08x",pagePhys));
+
+ // work out temporary mapping values...
+ TLinAddr tempLinAddr = iTempMap[0].iLinAddr;
+ TPte* tempPte = iTempMap[0].iPtePtr;
+
+ // temporarily map page...
+ *tempPte = pagePhys | iTempPteCached;
+ CacheMaintenance::SinglePteUpdated((TLinAddr)tempPte);
+ InvalidateTLBForPage(tempLinAddr|KKernelOsAsid);
+
+ // sort out cache for memory reuse...
+ CacheMaintenance::PageToPreserveAndReuse(tempLinAddr, type, KPageSize);
+
+ // invalidate temporary mapping...
+ *tempPte = KPteUnallocatedEntry;
+ CacheMaintenance::SinglePteUpdated((TLinAddr)tempPte);
+ InvalidateTLBForPage(tempLinAddr|KKernelOsAsid);
+
+ RamAllocLock::Flash();
+ }
+ RamAllocLock::Unlock();
+ }
+
+
+TInt DMemModelThread::Alias(TLinAddr aAddr, DMemModelProcess* aProcess, TInt aSize, TLinAddr& aAliasAddr, TUint& aAliasSize)
+//
+// Set up an alias mapping starting at address aAddr in specified process.
+// Note: Alias is removed if an exception is trapped by DThread::IpcExcHandler.
+//
+ {
+ TRACE2(("Thread %O Alias %08x+%x Process %O",this,aAddr,aSize,aProcess));
+ __NK_ASSERT_DEBUG(this==TheCurrentThread); // many bad things can happen if false
+ // If there is an existing alias it should be on the same process otherwise
+ // the os asid reference may be leaked.
+ __NK_ASSERT_DEBUG(!iAliasLinAddr || aProcess == iAliasProcess);
+
+ if(TUint(aAddr^KIPCAlias)<TUint(KIPCAliasAreaSize))
+ return KErrBadDescriptor; // prevent access to alias region
+
+ // Grab the mmu lock before opening a reference on os asid so that this thread
+ // is in an implicit critical section and therefore can't leak the reference by
+ // dying before iAliasLinAddr is set.
+ MmuLock::Lock();
+
+ TInt osAsid;
+ if (!iAliasLinAddr)
+ {// There isn't any existing alias.
+ // Open a reference on the aProcess's os asid so that it is not freed and/or reused
+ // while we are aliasing an address belonging to it.
+ osAsid = aProcess->TryOpenOsAsid();
+ if (osAsid < 0)
+ {// Couldn't open os asid so aProcess is no longer running.
+ MmuLock::Unlock();
+ return KErrBadDescriptor;
+ }
+ }
+ else
+ {
+ // Just read the os asid of the process being aliased we already have a reference on it.
+ osAsid = aProcess->OsAsid();
+ }
+
+ // Now we have the os asid check access to kernel memory.
+ if(aAddr >= KUserMemoryLimit && osAsid != (TUint)KKernelOsAsid)
+ {
+ if (!iAliasLinAddr)
+ {// Close the new reference as RemoveAlias won't do as iAliasLinAddr is not set.
+ aProcess->AsyncCloseOsAsid();
+ }
+ MmuLock::Unlock();
+ return KErrBadDescriptor; // prevent access to supervisor only memory
+ }
+
+ // Now we know all accesses to global memory are safe so check if aAddr is global.
+ if(aAddr >= KGlobalMemoryBase)
+ {
+ // address is in global section, don't bother aliasing it...
+ if (!iAliasLinAddr)
+ {// Close the new reference as not required.
+ aProcess->AsyncCloseOsAsid();
+ }
+ else
+ {// Remove the existing alias as it is not required.
+ DoRemoveAlias(iAliasLinAddr);
+ }
+ MmuLock::Unlock();
+ aAliasAddr = aAddr;
+ TInt maxSize = KChunkSize-(aAddr&KChunkMask);
+ aAliasSize = aSize<maxSize ? aSize : maxSize;
+ TRACE2(("DMemModelThread::Alias() abandoned as memory is globally mapped"));
+ return KErrNone;
+ }
+
+ TPde* pd = Mmu::PageDirectory(osAsid);
+ TInt pdeIndex = aAddr>>KChunkShift;
+ TPde pde = pd[pdeIndex];
+#ifdef __SMP__
+ TLinAddr aliasAddr;
+#else
+ TLinAddr aliasAddr = KIPCAlias+(aAddr&(KChunkMask & ~KPageMask));
+#endif
+ if(pde==iAliasPde && iAliasLinAddr)
+ {
+ // pde already aliased, so just update linear address...
+#ifdef __SMP__
+ __NK_ASSERT_DEBUG(iCpuRestoreCookie>=0);
+ aliasAddr = iAliasLinAddr & ~KChunkMask;
+ aliasAddr |= (aAddr & (KChunkMask & ~KPageMask));
+#endif
+ iAliasLinAddr = aliasAddr;
+ }
+ else
+ {
+ // alias PDE changed...
+ if(!iAliasLinAddr)
+ {
+ TheMmu.iAliasList.Add(&iAliasLink); // add to list if not already aliased
+#ifdef __SMP__
+ __NK_ASSERT_DEBUG(iCpuRestoreCookie==-1);
+ iCpuRestoreCookie = NKern::FreezeCpu(); // temporarily lock current thread to this processor
+#endif
+ }
+ iAliasPde = pde;
+ iAliasProcess = aProcess;
+#ifdef __SMP__
+ TSubScheduler& ss = SubScheduler(); // OK since we are locked to this CPU
+ aliasAddr = TLinAddr(ss.i_AliasLinAddr) + (aAddr & (KChunkMask & ~KPageMask));
+ iAliasPdePtr = (TPde*)(TLinAddr(ss.i_AliasPdePtr) + (osAsid << KPageTableShift));
+#endif
+ iAliasLinAddr = aliasAddr;
+ *iAliasPdePtr = pde;
+ }
+ TRACE2(("DMemModelThread::Alias() PDEntry=%x, iAliasLinAddr=%x",pde, aliasAddr));
+ LocalInvalidateTLBForPage(aliasAddr);
+ TInt offset = aAddr&KPageMask;
+ aAliasAddr = aliasAddr | offset;
+ TInt maxSize = KPageSize - offset;
+ aAliasSize = aSize<maxSize ? aSize : maxSize;
+ iAliasTarget = aAddr & ~KPageMask;
+
+ MmuLock::Unlock();
+
+ return KErrNone;
+ }
+
+
+void DMemModelThread::RemoveAlias()
+//
+// Remove alias mapping (if present)
+//
+ {
+ TRACE2(("Thread %O RemoveAlias", this));
+ __NK_ASSERT_DEBUG(this==TheCurrentThread); // many bad things can happen if false
+
+ TLinAddr addr = iAliasLinAddr;
+ if(addr)
+ {
+ MmuLock::Lock();
+
+ DoRemoveAlias(addr);
+
+ MmuLock::Unlock();
+ }
+ }
+
+
+/**
+Remove the alias mapping.
+
+@pre Mmulock held
+*/
+void DMemModelThread::DoRemoveAlias(TLinAddr aAddr)
+ {
+ iAliasLinAddr = 0;
+ iAliasPde = KPdeUnallocatedEntry;
+ *iAliasPdePtr = KPdeUnallocatedEntry;
+ SinglePdeUpdated(iAliasPdePtr);
+ __NK_ASSERT_DEBUG((aAddr&KPageMask)==0);
+ LocalInvalidateTLBForPage(aAddr);
+ iAliasLink.Deque();
+#ifdef __SMP__
+ __NK_ASSERT_DEBUG(iCpuRestoreCookie>=0);
+ NKern::EndFreezeCpu(iCpuRestoreCookie);
+ iCpuRestoreCookie = -1;
+#endif
+ // Must close the os asid while the mmu lock is held to prevent it being
+ // leaked, however this requires that it is closed asynchronously as can't
+ // delete os asid with mmu lock held.
+ iAliasProcess->AsyncCloseOsAsid();
+ }
+
+
+TInt M::DemandPagingFault(TAny* aExceptionInfo)
+ {
+ TX86ExcInfo& exc=*(TX86ExcInfo*)aExceptionInfo;
+ if(exc.iExcId!=EX86VectorPageFault)
+ return KErrAbort; // not a page fault
+
+ /*
+ Meanings of exc.iExcErrorCode when exception type is EX86VectorPageFault...
+
+ Bit 0 0 The fault was caused by a non-present page.
+ 1 The fault was caused by a page-level protection violation.
+ Bit 1 0 The access causing the fault was a read.
+ 1 The access causing the fault was a write.
+ Bit 2 0 The access causing the fault originated when the processor was executing in supervisor mode.
+ 1 The access causing the fault originated when the processor was executing in user mode.
+ Bit 3 0 The fault was not caused by reserved bit violation.
+ 1 The fault was caused by reserved bits set to 1 in a page directory.
+ Bit 4 0 The fault was not caused by an instruction fetch.
+ 1 The fault was caused by an instruction fetch.
+ */
+
+ // check access type...
+ TUint accessPermissions = EUser; // we only allow paging of user memory
+ if(exc.iExcErrorCode&(1<<1))
+ accessPermissions |= EReadWrite;
+
+ // let TheMmu handle the fault...
+ return TheMmu.HandlePageFault(exc.iEip, exc.iFaultAddress, accessPermissions, aExceptionInfo);
+ }
+
+