diff -r 000000000000 -r a41df078684a brdbootldr/ubootldr/ubootldrldd/ubootldrldd.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/brdbootldr/ubootldr/ubootldrldd/ubootldrldd.cpp Mon Oct 19 15:55:17 2009 +0100 @@ -0,0 +1,353 @@ +// Copyright (c) 2005-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 +#include +#include "ubootldrldd.h" + +static TInt ChunkDestroyedCount=1; // Test counter + +// +// Class definitions +// + +class DUBootldrFactory : public DLogicalDevice + { +public: + ~DUBootldrFactory(); + virtual TInt Install(); + virtual void GetCaps(TDes8& aDes) const; + virtual TInt Create(DLogicalChannelBase*& aChannel); + void LockWait(); + void LockSignal(); +private: + NFastMutex iLock; + }; + +class DUBootldrChannel : public DLogicalChannelBase + { +public: + ~DUBootldrChannel(); + virtual TInt DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer); + virtual TInt Request(TInt aFunction, TAny* a1, TAny* a2); + DChunk* OpenChunk(TLinAddr* aKernelAddr=0, TInt* aMaxSize=0); + inline void LockWait() + { iFactory->LockWait(); } + inline void LockSignal() + { iFactory->LockSignal(); } +public: + DUBootldrFactory* iFactory; + DChunk* iChunk; + TLinAddr iKernelAddress; + TInt iMaxSize; + }; + +class TChunkCleanup : public TDfc + { +public: + TChunkCleanup(DUBootldrFactory* aFactory,TBool aReleasePhysicalMemory); + ~TChunkCleanup(); + static void ChunkDestroyed(TChunkCleanup* aSelf); + void Cancel(); +public: + DUBootldrFactory* iFactory; + }; + +// +// TChunkCleanup +// + +TChunkCleanup::TChunkCleanup(DUBootldrFactory* aFactory,TBool aReleasePhysicalMemory) + : TDfc((TDfcFn)TChunkCleanup::ChunkDestroyed,this,Kern::SvMsgQue(),0) + , iFactory(0) + { + aFactory->Open(); + iFactory = aFactory; + } + +TChunkCleanup::~TChunkCleanup() + { + if(iFactory) + iFactory->Close(0); + } + +void TChunkCleanup::ChunkDestroyed(TChunkCleanup* aSelf) + { + DUBootldrFactory* factory = aSelf->iFactory; + if(factory) + { + factory->LockWait(); + ++ChunkDestroyedCount; + factory->LockSignal(); + } + delete aSelf; + } + +void TChunkCleanup::Cancel() + { + if(iFactory) + { + iFactory->Close(0); + iFactory = 0; + } + }; + +// +// DUBootldrFactory +// + +TInt DUBootldrFactory::Install() + { + return SetName(&KBootldrLddName); + } + +DUBootldrFactory::~DUBootldrFactory() + { + } + +void DUBootldrFactory::GetCaps(TDes8& /*aDes*/) const + { + // Not used but required as DLogicalDevice::GetCaps is pure virtual + } + +TInt DUBootldrFactory::Create(DLogicalChannelBase*& aChannel) + { + aChannel = NULL; + DUBootldrChannel* channel=new DUBootldrChannel; + if(!channel) + return KErrNoMemory; + channel->iFactory = this; + aChannel = channel; + return KErrNone; + } + +void DUBootldrFactory::LockWait() + { + NKern::FMWait(&iLock); + } + +void DUBootldrFactory::LockSignal() + { + NKern::FMSignal(&iLock); + } + +DECLARE_STANDARD_LDD() + { + return new DUBootldrFactory; + } + +// +// DUBootldrChannel +// + +TInt DUBootldrChannel::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& /*aVer*/) + { + return KErrNone; + } + +DUBootldrChannel::~DUBootldrChannel() + { + if(iChunk) + iChunk->Close(0); + } + +DChunk* DUBootldrChannel::OpenChunk(TLinAddr* aKernelAddr,TInt* aMaxSize) + { + __ASSERT_CRITICAL // Thread must be in critical section (to avoid leaking access count on chunk) + LockWait(); + DChunk* chunk=iChunk; + if(chunk) + if(chunk->Open()!=KErrNone) + chunk = NULL; + if(aKernelAddr) + *aKernelAddr = chunk ? iKernelAddress : NULL; + if(aMaxSize) + *aMaxSize = chunk ? iMaxSize : 0; + LockSignal(); + return chunk; + } + + +TUint8 ReadByte(volatile TUint8* aPtr) + { + return *aPtr; + } + + +TInt DUBootldrChannel::Request(TInt aFunction, TAny* a1, TAny* a2) + { +// Kern::Printf("Request a1 0x%x a2 0x%x", (TUint)a1, (TUint)a2); + TInt r=KErrNotSupported; + + switch(aFunction) + { + + case RUBootldrLdd::ECreateChunk: + { + if(ChunkDestroyedCount==0) + NKern::Sleep(NKern::TimerTicks(100)); // Go idle for a while to let chunk cleanup DFCs to be called + + NKern::ThreadEnterCS(); + TInt chunksize = (TInt)a1; + + TChunkCleanup* cleanup = new TChunkCleanup(this->iFactory,ETrue); + if(!cleanup) + { + NKern::ThreadLeaveCS(); + return KErrNoMemory; + } + + // Try and create chunk... + DChunk* chunk; + TChunkCreateInfo info; + + info.iType=TChunkCreateInfo::ESharedKernelSingle; + info.iMaxSize = chunksize; + info.iMapAttr = EMapAttrFullyBlocking; + info.iOwnsMemory = EFalse; + info.iDestroyedDfc = cleanup; + + TUint32 mapAttr; + TUint32 kernAddr; + r = Kern::ChunkCreate(info, chunk, kernAddr, mapAttr); + if(r!=KErrNone) + { + delete cleanup; + NKern::ThreadLeaveCS(); + return r; + } + + // Setup data members + LockWait(); + if(iChunk) + r = KErrAlreadyExists; + else + { + if(r==KErrNone) + { + iChunk = chunk; + iKernelAddress = kernAddr; + iMaxSize = info.iMaxSize; + ChunkDestroyedCount = 0; + } + } + LockSignal(); + + if(r!=KErrNone) + { + // There was an error, so discard created chunk + cleanup->Cancel(); + Kern::ChunkClose(chunk); + NKern::ThreadLeaveCS(); + return r; + } + + NKern::ThreadLeaveCS(); + + // Write back kernel address of chunk + if(a2) + kumemput32(a2,(TAny*)&kernAddr,4); + + return KErrNone; + } + + + case RUBootldrLdd::EGetChunkHandle: + { + NKern::ThreadEnterCS(); + DChunk* chunk=OpenChunk(); + if(chunk) + { + r = Kern::MakeHandleAndOpen(0,chunk); + chunk->Close(0); + } + else + r = KErrNotFound; + NKern::ThreadLeaveCS(); + return r; + } + + + case RUBootldrLdd::ECloseChunkHandle: + { + NKern::ThreadEnterCS(); + r = Kern::CloseHandle(0,(TInt)a1); + NKern::ThreadLeaveCS(); + return r; + } + + + case RUBootldrLdd::ECommitMemory: + { + NKern::ThreadEnterCS(); + TUint32 chunkKernelAddress; + DChunk* chunk=OpenChunk(&chunkKernelAddress); + if(chunk) + { + TUint sz=(TUint)a1; + TUint physaddr=(TUint)a2; + + // Kern::Printf("Commit chunk = 0x%x sz = 0x%x, addr = 0x%x", chunk, sz, physaddr); // XXX + + // LDD i/f guarantees page alignment of physaddr + r = Kern::ChunkCommitPhysical(chunk,0,sz,physaddr); + // chunk->Close(0); + } + else + r = KErrNotFound; + NKern::ThreadLeaveCS(); + return r; + } + + + case RUBootldrLdd::EIsDestroyed: + { + // First wait for short while to allow idle thread to run and do + // cleanup of chunk + NKern::Sleep(NKern::TimerTicks(100)); + return ChunkDestroyedCount; + } + + + case RUBootldrLdd::ECloseChunk: + { + NKern::ThreadEnterCS(); + + // Claim ownership of the chunk + LockWait(); + DChunk* chunk=iChunk; + iChunk = 0; + LockSignal(); + + // Close the chunk + if(chunk) + r = Kern::ChunkClose(chunk); + else + r = KErrNotFound; + + NKern::ThreadLeaveCS(); + return r; + } + case RUBootldrLdd::ERestart: + { + TInt aReason = (TInt)a1; + // Kern::Printf("Restart:: %d", aReason); + Kern::Restart(aReason); + return KErrNone; // Notreached + } + default: + return KErrNotSupported; + } + }