diff -r 000000000000 -r a41df078684a kernel/eka/memmodel/epoc/direct/mchunk.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/memmodel/epoc/direct/mchunk.cpp Mon Oct 19 15:55:17 2009 +0100 @@ -0,0 +1,451 @@ +// Copyright (c) 1994-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// e32\memmodel\epoc\direct\mchunk.cpp +// +// + +#include + +DMemModelChunk::~DMemModelChunk() + { + __KTRACE_OPT(KTHREAD,Kern::Printf("DMemModelChunk destruct %O",this)); + if (iRegionSize) + { + MM::WaitRamAlloc(); + MM::FreeRegion(iRegionBase,iRegionSize); + __KTRACE_OPT(KMEMTRACE, Kern::Printf("MT:D %d %x %O",NTickCount(),this,this);); + MM::SignalRamAlloc(); +#ifdef BTRACE_CHUNKS + BTraceContext4(BTrace::EChunks,BTrace::EChunkDestroyed,this); +#endif + } + iRegionSize=0; + + TDfc* dfc = (TDfc*)__e32_atomic_swp_ord_ptr(&iDestroyedDfc, 0); + if(dfc) + dfc->Enque(); + } + + +TUint8* DMemModelChunk::Base(DProcess* aProcess) + { + return iBase; + } + + +TInt DMemModelChunk::DoCreate(SChunkCreateInfo& anInfo) + { + __ASSERT_COMPILE(!(EMMChunkAttributesMask & EChunkAttributesMask)); + + if(iAttributes&EMemoryNotOwned) + return KErrNotSupported; + if (anInfo.iMaxSize<=0) + return KErrArgument; + TInt r=KErrNone; + iMaxSize=MM::RoundToBlockSize(anInfo.iMaxSize); + switch (anInfo.iType) + { + case EDll: + case EUserCode: + case EUserSelfModCode: + case EUserData: + case EDllData: + case ESharedKernelSingle: + case ESharedKernelMultiple: + case ESharedIo: + case EKernelMessage: + MM::WaitRamAlloc(); + r=MM::AllocRegion(iRegionBase, iMaxSize); + if (r==KErrNone) + iRegionSize=iMaxSize; + else + MM::AllocFailed=ETrue; + MM::SignalRamAlloc(); + iBase=(TUint8*)iRegionBase; + iSize=iMaxSize; + if(r==KErrNone) + { + iMapAttr = EMapAttrCachedMax; + __KTRACE_OPT(KMMU,Kern::Printf("DMemModelChunk::DoCreate clear %x+%x",iRegionBase,iRegionSize)); + + // Clear memory to value determined by chunk member + memset((TAny*)iRegionBase, iClearByte, MM::RoundToBlockSize(iRegionSize)); + } + break; + default: + break; + } + + __KTRACE_OPT(KMMU,Kern::Printf("DMemModelChunk::DoCreate %O ret %d",this,r)); + __KTRACE_OPT(KMMU,Kern::Printf("RegionBase=%08x, RegionSize=%08x",iRegionBase,iRegionSize)); + __KTRACE_OPT(KMEMTRACE, {MM::WaitRamAlloc();Kern::Printf("MT:C %d %x %O",NTickCount(),this,this);MM::SignalRamAlloc();}); +#ifdef BTRACE_CHUNKS + TKName nameBuf; + Name(nameBuf); + BTraceContextN(BTrace::EChunks,BTrace::EChunkCreated,this,iMaxSize,nameBuf.Ptr(),nameBuf.Size()); + if(iOwningProcess) + BTrace8(BTrace::EChunks,BTrace::EChunkOwner,this,iOwningProcess); + BTraceContext12(BTrace::EChunks,BTrace::EChunkInfo,this,iChunkType,iAttributes); +#endif + return r; + } + +void DMemModelChunk::SetFixedAddress(TLinAddr anAddr, TInt aSize) + { + __KTRACE_OPT(KMMU,Kern::Printf("DMemModelChunk %O SetFixedAddress %08X size %08X",this,anAddr,aSize)); + iSize=MM::RoundToBlockSize(aSize); + if (iSize>iMaxSize) + iMaxSize=iSize; + iBase=(TUint8*)anAddr; + } + +TInt DMemModelChunk::Adjust(TInt aNewSize) +// +// Adjust a standard chunk. +// + { + + __KTRACE_OPT(KMMU,Kern::Printf("DMemModelChunk::Adjust %08x",aNewSize)); + if (iAttributes & (EDoubleEnded|EDisconnected)) + return KErrGeneral; + if (aNewSize<0 || aNewSize>iMaxSize) + return KErrArgument; + + __KTRACE_OPT(KMMU,Kern::Printf("DMemModelChunk %O adjusted to %x",this,iSize)); + __KTRACE_OPT(KMEMTRACE, {MM::WaitRamAlloc();Kern::Printf("MT:A %d %x %x %O",NTickCount(),this,iSize,this);MM::SignalRamAlloc();}); + return KErrNone; + } + +TInt DMemModelChunk::AdjustDoubleEnded(TInt aBottom, TInt aTop) +// +// Adjust a double-ended chunk. +// + { + + __KTRACE_OPT(KMMU,Kern::Printf("DMemModelChunk::AdjustDoubleEnded %x-%x",aBottom,aTop)); + if ((iAttributes & (EDoubleEnded|EDisconnected))!=EDoubleEnded) + return KErrGeneral; + if (aTop<0 || aBottom<0 || aTopiMaxSize) + return KErrArgument; + TInt newSize=aTop-aBottom; + if (newSize>iMaxSize) + return KErrArgument; + iStartPos=aBottom; + + __KTRACE_OPT(KMMU,Kern::Printf("DMemModelChunk %O adjusted to %x+%x",this,iStartPos,iSize)); + __KTRACE_OPT(KMEMTRACE, {MM::WaitRamAlloc();Kern::Printf("MT:A %d %x %x %O",NTickCount(),this,iSize,this);MM::SignalRamAlloc();}); + return KErrNone; + } + +TInt DMemModelChunk::Address(TInt aOffset, TInt aSize, TLinAddr& aKernelAddress) + { + if(TUint(aOffset)>=TUint(iMaxSize)) + return KErrArgument; + if(TUint(aOffset+aSize)>TUint(iMaxSize)) + return KErrArgument; + if(aSize<=0) + return KErrArgument; + aKernelAddress = (TLinAddr)iBase+aOffset; + return KErrNone; + } + +TInt DMemModelChunk::PhysicalAddress(TInt aOffset, TInt aSize, TLinAddr& aKernelAddress, TUint32& aPhysicalAddress, TUint32* aPhysicalPageList) + { + TInt r=Address(aOffset,aSize,aKernelAddress); + if(r!=KErrNone) + return r; + + TPhysAddr physStart = Epoc::LinearToPhysical(aKernelAddress); + + TInt pageShift = 12; + TUint32 page = aKernelAddress>>pageShift<>pageShift<iMaxSize) + return KErrArgument; + if(LOGICAL_XOR((TInt)aCommitType&DChunk::ECommitPhysicalMask, iAttributes&DChunk::EMemoryNotOwned)) + return KErrNotSupported; // Commit type doesn't match 'memory owned' type + + if((TInt)aCommitType&DChunk::ECommitPhysicalMask) + return KErrNotSupported; + if(aCommitType==DChunk::ECommitContiguous) + { + // We can't commit contiguous memory, we just have to take what's already there. + // So check to see if memory is contiguous, and if not, return KErrNoMemory - + // which is what other Memory Models do if they can't find enough contiguous RAM. + TLinAddr kernAddr; + if(PhysicalAddress(aOffset,aSize,kernAddr,*aExtraArg)!=KErrNone) + return KErrNoMemory; + } + else if(aCommitType!=DChunk::ECommitDiscontiguous) + return KErrArgument; + + return KErrNone; + } + +TInt DMemModelChunk::Allocate(TInt aSize, TInt aGuard, TInt aAlign) +// +// Allocate offset and commit to a disconnected chunk. +// + { + __KTRACE_OPT(KMMU,Kern::Printf("DMemModelChunk::Allocate %x %x %d",aSize,aGuard,aAlign)); + if ((iAttributes & (EDoubleEnded|EDisconnected))!=EDisconnected) + return KErrGeneral; + if (aSize<=0 || aSize>iMaxSize) + return KErrArgument; + TInt r=KErrNotSupported; + __KTRACE_OPT(KMMU,Kern::Printf("DMemModelChunk::Allocate returns %x",r)); + return r; + } + +TInt DMemModelChunk::Decommit(TInt anOffset, TInt aSize) +// +// Decommit from a disconnected chunk. +// + { + __KTRACE_OPT(KMMU,Kern::Printf("DMemModelChunk::Decommit %x+%x",anOffset,aSize)); + if ((iAttributes & (EDoubleEnded|EDisconnected))!=EDisconnected) + return KErrGeneral; + if (anOffset<0 || aSize<0 || (anOffset+aSize)>iMaxSize) + return KErrArgument; + return KErrNone; + } + +void DMemModelChunk::Substitute(TInt /*aOffset*/, TPhysAddr /*aOldAddr*/, TPhysAddr /*aNewAddr*/) + { + MM::Panic(MM::EUnsupportedOperation); + } + +TInt DMemModelChunk::Unlock(TInt anOffset, TInt aSize) + { + __KTRACE_OPT(KMMU,Kern::Printf("DMemModelChunk::Decommit %x+%x",anOffset,aSize)); + if (!(iAttributes&ECache)) + return KErrGeneral; + if ((iAttributes & (EDoubleEnded|EDisconnected))!=EDisconnected) + return KErrGeneral; + if (anOffset<0 || aSize<0 || (anOffset+aSize)>iMaxSize) + return KErrArgument; + return KErrNone; + } + +TInt DMemModelChunk::Lock(TInt anOffset, TInt aSize) + { + __KTRACE_OPT(KMMU,Kern::Printf("DMemModelChunk::Decommit %x+%x",anOffset,aSize)); + if (!(iAttributes&ECache)) + return KErrGeneral; + if ((iAttributes & (EDoubleEnded|EDisconnected))!=EDisconnected) + return KErrGeneral; + if (anOffset<0 || aSize<0 || (anOffset+aSize)>iMaxSize) + return KErrArgument; + return KErrNone; + } + +TInt DMemModelChunk::CheckAccess() + { + DProcess* pP=TheCurrentThread->iOwningProcess; + if (iAttributes&EPrivate) + { + if (iOwningProcess && iOwningProcess!=pP && pP!=K::TheKernelProcess) + return KErrAccessDenied; + } + return KErrNone; + } + +TUint32 MM::RoundToBlockSize(TUint32 aSize) + { + TUint32 m=MM::RamBlockSize-1; + return (aSize+m)&~m; + } + +void MM::FreeRegion(TLinAddr aBase, TInt aSize) + { + __KTRACE_OPT(KMMU,Kern::Printf("MM::FreeRegion base %08x size %08x",aBase,aSize)); + aSize=MM::RoundToBlockSize(aSize); + __ASSERT_ALWAYS(aBase>=MM::UserDataSectionBase && aBase+aSize<=MM::UserDataSectionEnd, MM::Panic(MM::EFreeInvalidRegion)); + TInt block=(aBase-MM::UserDataSectionBase)>>MM::RamBlockShift; + TInt nBlocks=aSize>>MM::RamBlockShift; + MM::RamAllocator->Free(block, nBlocks); + } + +TInt MM::AllocRegion(TLinAddr& aBase, TInt aSize, TInt aAlign) + { + __KTRACE_OPT(KMMU,Kern::Printf("MM::AllocRegion size 0x%x align %d",aSize,aAlign)); + TInt align=Max(aAlign-MM::RamBlockShift, 0); + TInt nBlocks=MM::RoundToBlockSize(aSize)>>MM::RamBlockShift; + TInt base=(TInt)(MM::UserDataSectionBase>>MM::RamBlockShift); + TInt block=MM::RamAllocator->AllocAligned(nBlocks, align, base, ETrue); // returns first block number or -1 + if (block<0) + return KErrNoMemory; + MM::RamAllocator->Alloc(block,nBlocks); + aBase=MM::UserDataSectionBase+(block<MM::UserDataSectionEnd-aBase) + return KErrArgument; + TInt block=(aBase-MM::UserDataSectionBase)>>MM::RamBlockShift; + TInt nBlocks=aSize>>MM::RamBlockShift; + if (MM::RamAllocator->NotFree(block, nBlocks)) + return KErrInUse; + MM::RamAllocator->Alloc(block, nBlocks); + return KErrNone; + } + +// Allocate a physically contiguous region +TInt MM::AllocContiguousRegion(TLinAddr& aBase, TInt aSize, TInt aAlign) + { +#ifndef __CPU_HAS_MMU + return MM::AllocRegion(aBase, aSize, aAlign); +#else + __KTRACE_OPT(KMMU,Kern::Printf("MM::AllocContiguousRegion size 0x%x align %d",aSize,aAlign)); + TBitMapAllocator* sa = MM::SecondaryAllocator; + if (!sa) + return MM::AllocRegion(aBase, aSize, aAlign); // only one physical bank + + TBitMapAllocator* ra = MM::RamAllocator; + TInt align=Max(aAlign-MM::RamBlockShift, 0); + TUint32 alignmask = (1u<>MM::RamBlockShift; + TInt base=(TInt)(MM::UserDataSectionBase>>MM::RamBlockShift); + const SRamBank* banks = (const SRamBank*)TheSuperPage().iRamBootData; + const SRamBank* pB = banks; + TInt bnum = 0; + TInt block = -1; + for (; pB->iSize; ++pB) + { + TInt nb = pB->iSize >> MM::RamBlockShift; + sa->CopyAlignedRange(ra, bnum, nb); + TInt basealign = (base + bnum) & alignmask; + block = sa->AllocAligned(nBlocks, align, basealign, ETrue); // returns first block number or -1 + if (block>=0) + break; + bnum += nb; + } + if (pB->iSize == 0) + return KErrNoMemory; + MM::RamAllocator->Alloc(block + bnum, nBlocks); + aBase = MM::UserDataSectionBase + ((block + bnum)<iSize; ++pB) + { + if (aAddr >= pB->iBase) + { + TUint32 offset = aAddr - pB->iBase; + if (offset < pB->iSize) + { + TInt bn = bnum + TInt(offset>>MM::RamBlockShift); + __KTRACE_OPT(KMMU,Kern::Printf("MM::BlockNumber %08x->%x",aAddr,bn)); + return bn; + } + } + TInt nb = pB->iSize >> MM::RamBlockShift; + bnum += nb; + } + return KErrNotFound; + } + +/******************************************** + * Hardware chunk abstraction + ********************************************/ + +/** + @pre Call in a thread context. + @pre Interrupts must be enabled. + @pre Kernel must be unlocked. + @pre No fast mutex can be held. + @pre Calling thread must be in a critical section. + */ +EXPORT_C TInt DPlatChunkHw::New(DPlatChunkHw*& aChunk, TPhysAddr aAddr, TInt aSize, TUint aAttribs) + { + CHECK_PRECONDITIONS(MASK_THREAD_CRITICAL,"DPlatChunkHw::New"); + __KTRACE_OPT(KMMU,Kern::Printf("DPlatChunkHw::New phys=%08x, size=%x, attribs=%x",aAddr,aSize,aAttribs)); + aChunk=NULL; + if (aSize<=0) + return KErrArgument; + DPlatChunkHw* pC=new DPlatChunkHw; + if (!pC) + return KErrNoMemory; + __KTRACE_OPT(KMMU,Kern::Printf("DPlatChunkHw created at %08x",pC)); + + pC->iPhysAddr=aAddr; + pC->iLinAddr=aAddr; + pC->iSize=aSize; + aChunk=pC; + return KErrNone; + } + + +void DMemModelChunk::BTracePrime(TInt aCategory) + { + DChunk::BTracePrime(aCategory); + +#ifdef BTRACE_CHUNKS + if (aCategory == BTrace::EChunks || aCategory == -1) + { + BTrace12(BTrace::EChunks, BTrace::EChunkMemoryAllocated,this,0,this->iSize); + } +#endif + }