diff -r 000000000000 -r a41df078684a kernel/eka/memmodel/epoc/flexible/mmu/mm.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/memmodel/epoc/flexible/mmu/mm.cpp Mon Oct 19 15:55:17 2009 +0100 @@ -0,0 +1,1136 @@ +// Copyright (c) 2007-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 "memmodel.h" +#include "mm.h" +#include "mmu.h" +#include "mobject.h" +#include "mmapping.h" +#include "mmanager.h" +#include "mpdalloc.h" +#include "mptalloc.h" +#include "mpager.h" +#include "maddressspace.h" + + + + +// +// DMutexPool +// + +DMutexPool::~DMutexPool() + { + TUint i; + for(i=0; iClose(0); + } + Kern::Free(iMembers); + } + + +TInt DMutexPool::Create(TUint aCount, const TDesC* aName, TUint aOrder) + { + if(aCount>EMaxPoolSize) + return KErrTooBig; + + iMembers = (SMember*)Kern::AllocZ(aCount*sizeof(SMember)); + if(!iMembers) + return KErrNoMemory; + + iCount = aCount; + + TInt r = KErrNone; + TUint i; + for(i=0; i=iCount) + next = 0; + } + while(next!=iNext); + // use found mutex... + ++iMembers[next].iUseCount; + poolMutex = (next*2)+1; // mutex index*2 | 1 + // update next... + if(++next>=iCount) + next = 0; + iNext = next; + } + + DMutex* mutex = (DMutex*)poolMutex; + if(poolMutex&1) + { + // mutex is a pool mutex, get pointer, and update wait count... + SMember* member = &iMembers[(poolMutex&KMutexPoolIndexMask)>>1]; + mutex = member->iMutex; + poolMutex += KMutexPoolWaitCountIncrement; + __NK_ASSERT_ALWAYS(poolMutex>=KMutexPoolWaitCountIncrement); + aMutexRef = (DMutex*)poolMutex; + } + + mutex->Wait(); + + NKern::UnlockSystem(); + } + + +void DMutexPool::Signal(DMutex*& aMutexRef) + { + NKern::LockSystem(); + + TUintPtr poolMutex = (TUintPtr)aMutexRef; + __NK_ASSERT_ALWAYS(poolMutex); + + DMutex* mutex = (DMutex*)poolMutex; + + if(poolMutex&1) + { + // mutex is a pool mutex, get pointer, and update wait count... + SMember* member = &iMembers[(poolMutex&KMutexPoolIndexMask)>>1]; + mutex = member->iMutex; + __NK_ASSERT_ALWAYS(poolMutex>=KMutexPoolWaitCountIncrement); + poolMutex -= KMutexPoolWaitCountIncrement; + if(poolMutexiUseCount; + poolMutex = 0; + } + aMutexRef = (DMutex*)poolMutex; + } + + mutex->Signal(); + } + + +TBool DMutexPool::IsHeld(DMutex*& aMutexRef) + { + TBool held = false; + NKern::LockSystem(); + TUintPtr poolMutex = (TUintPtr)aMutexRef; + if(poolMutex) + { + DMutex* mutex = (DMutex*)poolMutex; + if(poolMutex&1) + { + SMember* member = &iMembers[(poolMutex&KMutexPoolIndexMask)>>1]; + mutex = member->iMutex; + } + held = mutex->iCleanup.iThread==&Kern::CurrentThread(); + } + NKern::UnlockSystem(); + return held; + } + + + +// +// DReferenceCountedObject +// + +DReferenceCountedObject::~DReferenceCountedObject() + { + __NK_ASSERT_DEBUG(iReferenceCount==0); + } + + +void DReferenceCountedObject::Open() + { + __ASSERT_CRITICAL + TBool ok = __e32_atomic_tas_ord32(&iReferenceCount, 1, 1, 0); + __NK_ASSERT_ALWAYS(ok); + } + + +TBool DReferenceCountedObject::TryOpen() + { + __ASSERT_CRITICAL + TBool ok = __e32_atomic_tas_ord32(&iReferenceCount, 1, 1, 0); + return ok; + } + + +TBool DReferenceCountedObject::CheckCloseIsSafe() + { + __ASSERT_CRITICAL +#ifdef _DEBUG + NFastMutex* fm = NKern::HeldFastMutex(); + if(fm) + { + Kern::Printf("DReferenceCountedObject[0x%08x]::Close() fast mutex violation %M",this,fm); + return false; + } + SDblQue& ml = TheCurrentThread->iMutexList; + if(!ml.IsEmpty()) + { + DMutex* m = _LOFF(ml.First(), DMutex, iOrderLink); + if(m->iOrder0); + if (__e32_atomic_tas_ord32(&iReferenceCount, 1, -1, 0) == 1) + delete this; + } + + +void DReferenceCountedObject::AsyncClose() + { + __ASSERT_CRITICAL + __NK_ASSERT_DEBUG(CheckAsyncCloseIsSafe()); + __NK_ASSERT_DEBUG(iReferenceCount>0); + if (__e32_atomic_tas_ord32(&iReferenceCount, 1, -1, 0) == 1) + AsyncDelete(); + } + + +// +// Memory object functions +// + +TInt MM::MemoryNew(DMemoryObject*& aMemory, TMemoryObjectType aType, TUint aPageCount, TMemoryCreateFlags aCreateFlags, TMemoryAttributes aAttributes) + { + TRACE(("MM::MemoryNew(?,0x%08x,0x%08x,0x%08x,0x%08x)",aType,aPageCount,aCreateFlags,*(TUint32*)&aAttributes)); + + DMemoryManager* manager; + if(aCreateFlags&EMemoryCreateCustomManager) + manager = (DMemoryManager*)aType; + else + { + switch(aType) + { + case EMemoryObjectUnpaged: + manager = TheUnpagedMemoryManager; + break; + case EMemoryObjectMovable: + manager = TheMovableMemoryManager; + break; + case EMemoryObjectPaged: + manager = TheDataPagedMemoryManager; + break; + case EMemoryObjectDiscardable: + manager = TheDiscardableMemoryManager; + break; + case EMemoryObjectHardware: + manager = TheHardwareMemoryManager; + break; + default: + manager = 0; + __NK_ASSERT_DEBUG(0); + break; + } + } + TMemoryCreateFlags flags = (TMemoryCreateFlags)(aCreateFlags&~(EMemoryCreateDemandPaged)); + TInt r = manager->New(aMemory,aPageCount,aAttributes,flags); + TRACE(("MM::MemoryNew returns %d, aMemory=0x%08x",r,aMemory)); +#ifdef BTRACE_FLEXIBLE_MEM_MODEL + if (r == KErrNone) + aMemory->BTraceCreate(); +#endif + return r; + } + + +TInt MM::MemoryClaimInitialPages(DMemoryObject* aMemory, TLinAddr aBase, TUint aSize, TMappingPermissions aPermissions, TBool aAllowGaps, TBool aAllowNonRamPages) + { + TRACE(("MM::MemoryClaimInitialPages(0x%08x,0x%08x,0x%08x,0x%08x,%d,%d)",aMemory,aBase,aPermissions,aSize,aAllowGaps!=0,aAllowNonRamPages!=0)); + TInt r = aMemory->ClaimInitialPages(aBase,aSize,aPermissions,aAllowGaps,aAllowNonRamPages); + TRACE(("MM::MemoryClaimInitialPages returns %d",r)); + __NK_ASSERT_DEBUG(r==KErrNone); + return r; + } + + +void MM::MemorySetLock(DMemoryObject* aMemory, DMutex* aLock) + { + aMemory->SetLock(aLock); + } + + +void MM::MemoryLock(DMemoryObject* aMemory) + { + MemoryObjectLock::Lock(aMemory); + } + + +void MM::MemoryUnlock(DMemoryObject* aMemory) + { + MemoryObjectLock::Unlock(aMemory); + } + + +void MM::MemoryDestroy(DMemoryObject*& aMemory) + { + DMemoryObject* memory = (DMemoryObject*)__e32_atomic_swp_ord_ptr(&aMemory, 0); + if (!memory) + return; + TRACE(("MM::MemoryDestroy(0x%08x)",memory)); +#ifdef BTRACE_FLEXIBLE_MEM_MODEL + BTraceContext4(BTrace::EFlexibleMemModel,BTrace::EMemoryObjectDestroy,memory); +#endif + memory->iManager->Destruct(memory); + } + + +TInt MM::MemoryAlloc(DMemoryObject* aMemory, TUint aIndex, TUint aCount) + { + TRACE(("MM::MemoryAlloc(0x%08x,0x%08x,0x%08x)",aMemory,aIndex,aCount)); + MemoryObjectLock::Lock(aMemory); + TInt r; + if(!aMemory->CheckRegion(aIndex,aCount)) + r = KErrArgument; + else + r = aMemory->iManager->Alloc(aMemory,aIndex,aCount); + MemoryObjectLock::Unlock(aMemory); + TRACE(("MM::MemoryAlloc returns %d",r)); + return r; + } + + +TInt MM::MemoryAllocContiguous(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TUint aAlign, TPhysAddr& aPhysAddr) + { + TRACE(("MM::MemoryAllocContiguous(0x%08x,0x%08x,0x%08x,%d,?)",aMemory,aIndex,aCount,aAlign)); + MemoryObjectLock::Lock(aMemory); + TInt r; + if(!aMemory->CheckRegion(aIndex,aCount)) + r = KErrArgument; + else + r = aMemory->iManager->AllocContiguous(aMemory,aIndex,aCount,MM::RoundToPageShift(aAlign),aPhysAddr); + MemoryObjectLock::Unlock(aMemory); + TRACE(("MM::MemoryAlloc returns %d (aPhysAddr=0x%08x)",r,aPhysAddr)); + return r; + } + + +void MM::MemoryFree(DMemoryObject* aMemory, TUint aIndex, TUint aCount) + { + TRACE(("MM::MemoryFree(0x%08x,0x%08x,0x%08x)",aMemory,aIndex,aCount)); + MemoryObjectLock::Lock(aMemory); + aMemory->ClipRegion(aIndex,aCount); + aMemory->iManager->Free(aMemory,aIndex,aCount); + MemoryObjectLock::Unlock(aMemory); + } + + +TInt MM::MemoryAddPages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TPhysAddr* aPages) + { + TRACE(("MM::MemoryAddPages(0x%08x,0x%08x,0x%08x,?)",aMemory,aIndex,aCount)); + MemoryObjectLock::Lock(aMemory); + TInt r; + if(!aMemory->CheckRegion(aIndex,aCount)) + r = KErrArgument; + else + r = aMemory->iManager->AddPages(aMemory,aIndex,aCount,aPages); + MemoryObjectLock::Unlock(aMemory); + TRACE(("MM::MemoryAddPages returns %d",r)); + return r; + } + + +TInt MM::MemoryAddContiguous(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TPhysAddr aPhysAddr) + { + TRACE(("MM::MemoryAddContiguous(0x%08x,0x%08x,0x%08x,0x%08x)",aMemory,aIndex,aCount,aPhysAddr)); + MemoryObjectLock::Lock(aMemory); + TInt r; + if(!aMemory->CheckRegion(aIndex,aCount)) + r = KErrArgument; + else + r = aMemory->iManager->AddContiguous(aMemory,aIndex,aCount,aPhysAddr); + MemoryObjectLock::Unlock(aMemory); + TRACE(("MM::MemoryAddContiguous returns %d",r)); + return r; + } + + +TUint MM::MemoryRemovePages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TPhysAddr* aPages) + { + TRACE(("MM::MemoryRemovePages(0x%08x,0x%08x,0x%08x)",aMemory,aIndex,aCount)); + MemoryObjectLock::Lock(aMemory); + aMemory->ClipRegion(aIndex,aCount); + TInt r = aMemory->iManager->RemovePages(aMemory,aIndex,aCount,aPages); + if(r<0) + r = 0; + MemoryObjectLock::Unlock(aMemory); + TRACE(("MM::MemoryRemovePages returns %d",r)); + return r; + } + + +TInt MM::MemoryAllowDiscard(DMemoryObject* aMemory, TUint aIndex, TUint aCount) + { + TRACE(("MM::MemoryAllowDiscard(0x%08x,0x%08x,0x%08x)",aMemory,aIndex,aCount)); + MemoryObjectLock::Lock(aMemory); + TInt r; + if(!aMemory->CheckRegion(aIndex,aCount)) + r = KErrArgument; + else + r = aMemory->iManager->AllowDiscard(aMemory,aIndex,aCount); + MemoryObjectLock::Unlock(aMemory); + TRACE(("MM::MemoryAllowDiscard returns %d",r)); + return r; + } + + +TInt MM::MemoryDisallowDiscard(DMemoryObject* aMemory, TUint aIndex, TUint aCount) + { + TRACE(("MM::MemoryDisallowDiscard(0x%08x,0x%08x,0x%08x)",aMemory,aIndex,aCount)); + MemoryObjectLock::Lock(aMemory); + TInt r; + if(!aMemory->CheckRegion(aIndex,aCount)) + r = KErrArgument; + else + r = aMemory->iManager->DisallowDiscard(aMemory,aIndex,aCount); + MemoryObjectLock::Unlock(aMemory); + TRACE(("MM::MemoryDisallowDiscard returns %d",r)); + return r; + } + + +TInt MM::MemoryPhysAddr(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TPhysAddr& aPhysicalAddress, TPhysAddr* aPhysicalPageList) + { + TRACE(("MM::MemoryPhysAddr(0x%08x,0x%08x,0x%08x,?,?)",aMemory,aIndex,aCount)); + TInt r = aMemory->PhysAddr(aIndex,aCount,aPhysicalAddress,aPhysicalPageList); + TRACE(("MM::MemoryPhysAddr returns %d aPhysicalAddress=0x%08x",r,aPhysicalAddress)); + return r; + } + + +void MM::MemoryBTracePrime(DMemoryObject* aMemory) + { + aMemory->BTraceCreate(); + aMemory->iMappings.Lock(); + TMappingListIter iter; + DMemoryMapping* mapping = (DMemoryMapping*)iter.Start(aMemory->iMappings); + while(mapping) + { + aMemory->iMappings.Unlock(); + mapping->BTraceCreate(); + aMemory->iMappings.Lock(); + mapping = (DMemoryMapping*)iter.Next(); + } + iter.Finish(); + aMemory->iMappings.Unlock(); + } + + +void MM::MemoryClose(DMemoryObject* aMemory) + { + aMemory->Close(); + } + + +TBool MM::MemoryIsNotMapped(DMemoryObject* aMemory) + { + TBool r = aMemory->iMappings.IsEmpty(); + TRACE2(("MM::MemoryIsNotMapped(0x%08x) returns %d",aMemory,r)); + return r; + } + +// +// Physical pinning +// + +TInt MM::PinPhysicalMemory(DMemoryObject* aMemory, DPhysicalPinMapping* aPinObject, TUint aIndex, TUint aCount, TBool aReadOnly, TPhysAddr& aAddress, TPhysAddr* aPages, TUint32& aMapAttr, TUint& aColour) + { + + if (!aMemory->CheckRegion(aIndex,aCount)) + return KErrArgument; + + TMappingPermissions permissions = aReadOnly ? ESupervisorReadOnly : ESupervisorReadWrite; + TInt r = aPinObject->Pin(aMemory, aIndex, aCount, permissions); + if (r == KErrNone) + { + r = aPinObject->PhysAddr(aIndex, aCount, aAddress, aPages); + if (r>=KErrNone) + { + r = KErrNone; //Do not report discontigious memory in return value. + const TMappingAttributes2& mapAttr2 = + MM::LegacyMappingAttributes(aMemory->Attributes(), permissions); + *(TMappingAttributes2*)&aMapAttr = mapAttr2; + } + else + { + aPinObject->Unpin(); + } + } + + aColour = 0; + return r; + } + + +TInt MM::MemoryWipe(DMemoryObject* aMemory) + { + __NK_ASSERT_ALWAYS(aMemory->iMappings.IsEmpty()); // can't be mapped otherwise confidentiality can't be guaranteed + TRACE2(("MM::MemoryWipe(0x%08x)",aMemory)); + MemoryObjectLock::Lock(aMemory); + TInt r = aMemory->iManager->Wipe(aMemory); + MemoryObjectLock::Unlock(aMemory); + return r; + } + + +TInt MM::MemorySetReadOnly(DMemoryObject* aMemory) + { + TRACE2(("MM::MemorySetReadOnly(0x%08x)",aMemory)); + MemoryObjectLock::Lock(aMemory); + TInt r = aMemory->SetReadOnly(); + MemoryObjectLock::Unlock(aMemory); + return r; + } + +// +// Mapping functions +// + +TInt MM::MappingNew(DMemoryMapping*& aMapping, DMemoryObject* aMemory, TMappingPermissions aPermissions, TInt aOsAsid, TMappingCreateFlags aFlags, TLinAddr aAddr, TUint aIndex, TUint aCount) + { + TRACE(("MM::MappingNew(?,0x%08x,0x%08x,%d,0x%08x,0x%08x,0x%08x,0x%08x)",aMemory, aPermissions, aOsAsid, aFlags, aAddr, aIndex, aCount)); + + /** + @todo Make mappings created with this function fail (panic?) if the are reused to map + another object. + */ + if(aCount==~0u) + aCount = aMemory->iSizeInPages-aIndex; + + // if memory object reserves all resources, make mappings also do so... + if(aMemory->iFlags&DMemoryObject::EReserveResources) + FlagSet(aFlags,EMappingCreateReserveAllResources); + + // check if mapping is for global user data... + if(aOsAsid==(TInt)KKernelOsAsid && aPermissions&EUser) + FlagSet(aFlags,EMappingCreateUserGlobalVirtual); + else + FlagClear(aFlags,EMappingCreateUserGlobalVirtual); + + // set paged attribute for mapping... + if(aMemory->IsDemandPaged()) + FlagSet(aFlags,EMappingCreateDemandPaged); + else + FlagClear(aFlags,EMappingCreateDemandPaged); + + DMemoryMapping* mapping = 0; + TInt r = KErrNone; + if(!aMemory->CheckRegion(aIndex,aCount)) + r = KErrArgument; + else + { + mapping = aMemory->CreateMapping(aIndex, aCount); + if(!mapping) + r = KErrNoMemory; + } + + if(!mapping) + { + // free any virtual address the mapping should have adopted... + if(aFlags&EMappingCreateAdoptVirtual) + MM::VirtualFree(aOsAsid, aAddr, aCount<Construct(aMemory->Attributes(), aFlags, aOsAsid, aAddr, aCount<Map(aMemory, aIndex, aCount, aPermissions); + if(r!=KErrNone) + { + mapping->Close(); + mapping = 0; + } + } + + aMapping = mapping; + TRACE(("MM::MappingNew returns %d (aMapping=0x%0x)",r,aMapping)); +#ifdef BTRACE_FLEXIBLE_MEM_MODEL + if (r == KErrNone) + aMapping->BTraceCreate(); +#endif + return r; + } + + +TInt MM::MappingNew(DMemoryMapping*& aMapping, TUint aCount, TInt aOsAsid, TMappingCreateFlags aFlags, TLinAddr aAddr, TLinAddr aColourOffset) + { + TRACE2(("MM::MappingNew(?,0x%08x,%d,0x%08x,0x%08x,0x%08x)",aCount, aOsAsid, aFlags, aAddr, aColourOffset)); + + FlagClear(aFlags,EMappingCreateDemandPaged); // mapping can't use demand paged page tables + + TInt r = KErrNone; + DMemoryMapping* mapping = new DFineMapping(); + if(!mapping) + r = KErrNoMemory; + + if(!mapping) + { + // free any virtual address the mapping should have adopted... + if(aFlags&EMappingCreateAdoptVirtual) + MM::VirtualFree(aOsAsid, aAddr, aCount<Construct(EMemoryAttributeStandard, aFlags, aOsAsid, aAddr, aCount<Close(); + mapping = 0; + } + } + + aMapping = mapping; + TRACE2(("MM::MappingNew returns %d (aMapping=0x%0x)",r,aMapping)); + + return r; + } + + +TInt MM::MappingMap(DMemoryMapping* aMapping, TMappingPermissions aPermissions, DMemoryObject* aMemory, TUint aIndex, TUint aCount) + { + TRACE2(("MM::MappingMap(0x%08x,0x%08x,0x%08x,0x%x,0x%x)",aMapping,aPermissions,aMemory,aIndex,aCount)); + if(aCount==~0u) + aCount = aMemory->iSizeInPages-aIndex; + TInt r = aMapping->Map(aMemory, aIndex, aCount, aPermissions); + TRACE2(("MM::MappingMap returns %d",r)); + return r; + } + + +void MM::MappingUnmap(DMemoryMapping* aMapping) + { + if(aMapping->IsAttached()) + { + TRACE2(("MM::MappingUnmap(0x%08x)",aMapping)); + aMapping->Unmap(); + } + } + + +void MM::MappingDestroy(DMemoryMapping*& aMapping) + { + DMemoryMapping* mapping = (DMemoryMapping*)__e32_atomic_swp_ord_ptr(&aMapping, 0); + if (!mapping) + return; + TRACE(("MM::MappingDestroy(0x%08x)",mapping)); +#ifdef BTRACE_FLEXIBLE_MEM_MODEL + BTraceContext4(BTrace::EFlexibleMemModel,BTrace::EMemoryMappingDestroy,mapping); +#endif + if(mapping->IsAttached()) + mapping->Unmap(); + mapping->Close(); + } + + +void MM::MappingDestroy(TLinAddr aAddr, TInt aOsAsid) + { + DMemoryMapping* mapping = AddressSpace[aOsAsid]->GetMapping(aAddr); + MM::MappingDestroy(mapping); + } + + +void MM::MappingAndMemoryDestroy(DMemoryMapping*& aMapping) + { + DMemoryMapping* mapping = (DMemoryMapping*)__e32_atomic_swp_ord_ptr(&aMapping, 0); + TRACE(("MM::MappingAndMemoryDestroy(0x%08x)",mapping)); + if (!mapping) + return; + DMemoryObject* memory = mapping->Memory(true); // safe because we assume owner hasn't unmapped mapping + MM::MappingDestroy(mapping); + MM::MemoryDestroy(memory); + } + + +void MM::MappingAndMemoryDestroy(TLinAddr aAddr, TInt aOsAsid) + { + DMemoryMapping* mapping = AddressSpace[aOsAsid]->GetMapping(aAddr); + MM::MappingAndMemoryDestroy(mapping); + } + + +TLinAddr MM::MappingBase(DMemoryMapping* aMapping) + { + TLinAddr base = aMapping->Base(); + TRACE2(("MM::MappingBase(0x%08x) returns 0x%08x",aMapping,base)); + return base; + } + + +TInt MM::MappingOsAsid(DMemoryMapping* aMapping) + { + return aMapping->OsAsid(); + } + + +DMemoryObject* MM::MappingGetAndOpenMemory(DMemoryMapping* aMapping) + { + MmuLock::Lock(); + DMemoryObject* memory = aMapping->Memory(); + if (memory) + memory->Open(); + MmuLock::Unlock(); + TRACE2(("MM::MappingGetAndOpenMemory(0x%08x) returns 0x%08x",aMapping,memory)); + return memory; + } + + +void MM::MappingClose(DMemoryMapping* aMapping) + { + TRACE2(("MM::MappingClose(0x%08x)",aMapping)); + aMapping->Close(); + } + + +DMemoryMapping* MM::FindMappingInThread(DMemModelThread* aThread, TLinAddr aAddr, TUint aSize, + TUint& aOffsetInMapping, TUint& aInstanceCount) + { + if(aAddr>=KGlobalMemoryBase) + { + // Address in global region, so look it up in kernel's address space... + return FindMappingInAddressSpace(KKernelOsAsid, aAddr, aSize, aOffsetInMapping, aInstanceCount); + } + + // Address in thread's process address space so open a reference to its os asid + // so that it remains valid for FindMappingInAddressSpace() call. + DMemModelProcess* process = (DMemModelProcess*)aThread->iOwningProcess; + TInt osAsid = process->TryOpenOsAsid(); + if (osAsid < 0) + {// The process no longer owns an address space so can't have any mappings. + return NULL; + } + + DMemoryMapping* r = FindMappingInAddressSpace(osAsid, aAddr, aSize, aOffsetInMapping, aInstanceCount); + + process->CloseOsAsid(); + return r; + } + + +DMemoryMapping* MM::FindMappingInAddressSpace( TUint aOsAsid, TLinAddr aAddr, TUint aSize, + TUint& aOffsetInMapping, TUint& aInstanceCount) + { + return AddressSpace[aOsAsid]->FindMapping(aAddr, aSize, aOffsetInMapping, aInstanceCount); + } + + + +// +// Address space +// + +TInt MM::AddressSpaceAlloc(TPhysAddr& aPageDirectory) + { + return DAddressSpace::New(aPageDirectory); + } + + +void MM::AddressSpaceFree(TUint aOsAsid) + { + AddressSpace[aOsAsid]->Close(); + } + + +void MM::AsyncAddressSpaceFree(TUint aOsAsid) + { + AddressSpace[aOsAsid]->AsyncClose(); + } + + +TInt MM::VirtualAllocCommon(TLinAddr& aLinAddr, TUint aSize, TBool aDemandPaged) + { + TRACE(("MM::VirtualAllocCommon(?,0x%08x,%d)",aSize,aDemandPaged)); + TUint pdeType = aDemandPaged ? EVirtualSlabTypeDemandPaged : 0; + TInt r = DAddressSpace::AllocateUserCommonVirtualMemory(aLinAddr, aSize, 0, aSize, pdeType); + TRACE(("MM::VirtualAllocCommon returns %d region=0x%08x+0x%08x",r,aLinAddr,aSize)); + return r; + } + + +void MM::VirtualFreeCommon(TLinAddr aLinAddr, TUint aSize) + { + TRACE(("MM::VirtualFreeCommon(0x%08x,0x%08x)",aLinAddr,aSize)); + DAddressSpace::FreeUserCommonVirtualMemory(aLinAddr, aSize); + } + + +TInt MM::VirtualAlloc(TInt aOsAsid, TLinAddr& aLinAddr, TUint aSize, TBool aDemandPaged) + { + TRACE(("MM::VirtualAlloc(?,%d,0x%08x,%d)",aOsAsid,aSize,aDemandPaged)); + TUint pdeType = aDemandPaged ? EVirtualSlabTypeDemandPaged : 0; + TInt r = AddressSpace[aOsAsid]->AllocateVirtualMemory(aLinAddr, aSize, 0, aSize, pdeType); + TRACE(("MM::VirtualAlloc returns %d region=0x%08x+0x%08x",r,aLinAddr,aSize)); + return r; + } + + +void MM::VirtualFree(TInt aOsAsid, TLinAddr aLinAddr, TUint aSize) + { + TRACE(("MM::VirtualFree(%d,0x%08x,0x%08x)",aOsAsid,aLinAddr,aSize)); + AddressSpace[aOsAsid]->FreeVirtualMemory(aLinAddr, aSize); + } + + + +// +// Init +// + +void MM::Init1() + { + TheMmu.Init1(); + } + + +extern DMutexPool MemoryObjectMutexPool; +extern DMutexPool AddressSpaceMutexPool; + +void MM::Init2() + { + TInt r; + + TheMmu.Init2(); + + // create mutex pools before calling any functions which require them... + _LIT(KAddressSpaceMutexName,"AddressSpaceMutex"); + r = AddressSpaceMutexPool.Create(4, &KAddressSpaceMutexName, KMutexOrdAddresSpace); + __NK_ASSERT_ALWAYS(r==KErrNone); + _LIT(KMemoryObjectMutexName,"MemoryObjectMutex"); + r = MemoryObjectMutexPool.Create(8, &KMemoryObjectMutexName, KMutexOrdMemoryObject); + __NK_ASSERT_ALWAYS(r==KErrNone); + + // use the Ram Allocator mutex for low-level memory functions... + DMutex* mmuAllocMutex = TheMmu.iRamAllocatorMutex; + + // memory cleanup needs initialising before any memory is freed... + TMemoryCleanup::Init2(); + + // initialise allocators used for MMU operations... + RPageArray::Init2A(); + PageTables.Init2(mmuAllocMutex); // must come before any other code which allocates memory objects + RPageArray::Init2B(mmuAllocMutex); + PageTables.Init2B(); + PageDirectories.Init2(); + + // initialise address spaces... + DAddressSpace::Init2(); + + // init pager... + ThePager.Init2(); + + TheMmu.Init2Final(); + } + + +/** HAL Function wrapper for the RAM allocator. +*/ +TInt RamHalFunction(TAny*, TInt aFunction, TAny* a1, TAny* a2) + { + return TheMmu.RamHalFunction(aFunction, a1, a2); + } + + +void MM::Init3() + { + __KTRACE_OPT2(KBOOT,KMMU,Kern::Printf("MM::Init3")); + ThePager.Init3(); + + // Register a HAL Function for the Ram allocator. + TInt r = Kern::AddHalEntry(EHalGroupRam, RamHalFunction, 0); + __NK_ASSERT_ALWAYS(r==KErrNone); + + TheMmu.Init3(); + } + + +TInt MM::InitFixedKernelMemory(DMemoryObject*& aMemory, + TLinAddr aStart, + TLinAddr aEnd, + TUint aInitSize, + TMemoryObjectType aType, + TMemoryCreateFlags aMemoryCreateFlags, + TMemoryAttributes aMemoryAttributes, + TMappingCreateFlags aMappingCreateFlags + ) + { + TUint maxSize = aEnd-aStart; + TInt r = MM::MemoryNew(aMemory, aType, MM::BytesToPages(maxSize), aMemoryCreateFlags, aMemoryAttributes); + if(r==KErrNone) + { + TBool allowGaps = aInitSize&1; // lower bit of size is set if region to be claimed contains gaps + aInitSize &= ~1; + r = MM::MemoryClaimInitialPages(aMemory,aStart,aInitSize,ESupervisorReadWrite,allowGaps); + if(r==KErrNone) + { + DMemoryMapping* mapping; + r = MM::MappingNew(mapping,aMemory,ESupervisorReadWrite,KKernelOsAsid,aMappingCreateFlags,aStart); + // prevent any further mappings of this memory, + // this is needed for realtime and OOM guarantees... + aMemory->DenyMappings(); + } + } + // Note, no cleanup is done if an error occurs because this function is only + // used at boot time and the system can't recover from an error + return r; + } + + +void MM::Panic(MM::TMemModelPanic aPanic) + { + Kern::Fault("MemModel", aPanic); + } + + +// +// +// + +TUint MM::BytesToPages(TUint aBytes) + { + if(aBytes&KPageMask) + Panic(EBadBytesToPages); + return aBytes>>KPageShift; + } + + +TUint MM::RoundToPageSize(TUint aSize) + { + return (aSize+KPageMask)&~KPageMask; + } + + +TUint MM::RoundToPageCount(TUint aSize) + { + return (aSize+KPageMask)>>KPageShift; + } + + +TUint MM::RoundToPageShift(TUint aShift) + { + return aShift>(TUint)KPageShift ? aShift-KPageShift : 0; + } + + +// +// +// + +void MM::ValidateLocalIpcAddress(TLinAddr aAddr, TUint aSize, TBool aWrite) + { + __NK_ASSERT_DEBUG(aSize); + + TLinAddr end = aAddr+aSize-1; + if(end=KUserLocalDataBase) + return; + + // if region overlaps alias region... + if(end>=KIPCAlias && aAddrRemoveAlias(); + // make sure start address is in alias region... + if(aAddriOwningProcess)->OsAsid()==(TInt)KKernelOsAsid) + return; // kernel can access everything + + // make sure address is in supervisor only region... + if(aAddr>KChunkShift]; + } +#endif + + +TMappingPermissions MM::MappingPermissions(TBool aUser, TBool aWrite, TBool aExecute) + { + TUint perm = 0; + if(aUser) + perm |= EUser; + if(aWrite) + perm |= EReadWrite; + if(aExecute) + perm |= EExecute; + return (TMappingPermissions)perm; + } + + +TInt MM::MappingPermissions(TMappingPermissions& aPermissions, TMappingAttributes2 aLegacyAttributes) + { + TUint attr2 = *(TUint32*)&aLegacyAttributes; + + TUint read = attr2&EMapAttrReadMask; + TUint write = (attr2&EMapAttrWriteMask)>>4; + TUint execute = (attr2&EMapAttrExecMask)>>8; + + read |= execute; // execute access requires read access + + if(write==0) // no write required + { + if((read&5)==0) + return KErrNotSupported; // neither supervisor nor user read specified + } + else if(write<4) // supervisor write required + { + if(read>=4) + return KErrNotSupported; // user read requested (but no user write) + } + + read |= write; // write access implies read access + + TUint user = read&4; + aPermissions = MappingPermissions(user,write,execute); + + return KErrNone; + } + + +TInt MM::MemoryAttributes(TMemoryAttributes& aAttributes, TMappingAttributes2 aLegacyAttributes) + { + TUint attr = aLegacyAttributes.Type(); + if (aLegacyAttributes.Shared()) + attr |= EMemoryAttributeShareable; + if (aLegacyAttributes.Parity()) + attr |= EMemoryAttributeUseECC; + aAttributes = Mmu::CanonicalMemoryAttributes((TMemoryAttributes)attr); + return KErrNone; + } + + +TMappingAttributes2 MM::LegacyMappingAttributes(TMemoryAttributes aAttributes, TMappingPermissions aPermissions) + { + TUint attr = Mmu::CanonicalMemoryAttributes(aAttributes); + return TMappingAttributes2 + ( + (TMemoryType)(attr&EMemoryAttributeTypeMask), + aPermissions&EUser, + aPermissions&EReadWrite, + aPermissions&EExecute, + attr&EMemoryAttributeShareable, + attr&EMemoryAttributeUseECC + ); + } + +