1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/brdbootldr/ubootldr/ubootldrldd/ubootldrldd.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,353 @@
1.4 +// Copyright (c) 2005-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of the License "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +//
1.18 +
1.19 +#include <kernel/kern_priv.h>
1.20 +#include <kernel/cache.h>
1.21 +#include "ubootldrldd.h"
1.22 +
1.23 +static TInt ChunkDestroyedCount=1; // Test counter
1.24 +
1.25 +//
1.26 +// Class definitions
1.27 +//
1.28 +
1.29 +class DUBootldrFactory : public DLogicalDevice
1.30 + {
1.31 +public:
1.32 + ~DUBootldrFactory();
1.33 + virtual TInt Install();
1.34 + virtual void GetCaps(TDes8& aDes) const;
1.35 + virtual TInt Create(DLogicalChannelBase*& aChannel);
1.36 + void LockWait();
1.37 + void LockSignal();
1.38 +private:
1.39 + NFastMutex iLock;
1.40 + };
1.41 +
1.42 +class DUBootldrChannel : public DLogicalChannelBase
1.43 + {
1.44 +public:
1.45 + ~DUBootldrChannel();
1.46 + virtual TInt DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer);
1.47 + virtual TInt Request(TInt aFunction, TAny* a1, TAny* a2);
1.48 + DChunk* OpenChunk(TLinAddr* aKernelAddr=0, TInt* aMaxSize=0);
1.49 + inline void LockWait()
1.50 + { iFactory->LockWait(); }
1.51 + inline void LockSignal()
1.52 + { iFactory->LockSignal(); }
1.53 +public:
1.54 + DUBootldrFactory* iFactory;
1.55 + DChunk* iChunk;
1.56 + TLinAddr iKernelAddress;
1.57 + TInt iMaxSize;
1.58 + };
1.59 +
1.60 +class TChunkCleanup : public TDfc
1.61 + {
1.62 +public:
1.63 + TChunkCleanup(DUBootldrFactory* aFactory,TBool aReleasePhysicalMemory);
1.64 + ~TChunkCleanup();
1.65 + static void ChunkDestroyed(TChunkCleanup* aSelf);
1.66 + void Cancel();
1.67 +public:
1.68 + DUBootldrFactory* iFactory;
1.69 + };
1.70 +
1.71 +//
1.72 +// TChunkCleanup
1.73 +//
1.74 +
1.75 +TChunkCleanup::TChunkCleanup(DUBootldrFactory* aFactory,TBool aReleasePhysicalMemory)
1.76 + : TDfc((TDfcFn)TChunkCleanup::ChunkDestroyed,this,Kern::SvMsgQue(),0)
1.77 + , iFactory(0)
1.78 + {
1.79 + aFactory->Open();
1.80 + iFactory = aFactory;
1.81 + }
1.82 +
1.83 +TChunkCleanup::~TChunkCleanup()
1.84 + {
1.85 + if(iFactory)
1.86 + iFactory->Close(0);
1.87 + }
1.88 +
1.89 +void TChunkCleanup::ChunkDestroyed(TChunkCleanup* aSelf)
1.90 + {
1.91 + DUBootldrFactory* factory = aSelf->iFactory;
1.92 + if(factory)
1.93 + {
1.94 + factory->LockWait();
1.95 + ++ChunkDestroyedCount;
1.96 + factory->LockSignal();
1.97 + }
1.98 + delete aSelf;
1.99 + }
1.100 +
1.101 +void TChunkCleanup::Cancel()
1.102 + {
1.103 + if(iFactory)
1.104 + {
1.105 + iFactory->Close(0);
1.106 + iFactory = 0;
1.107 + }
1.108 + };
1.109 +
1.110 +//
1.111 +// DUBootldrFactory
1.112 +//
1.113 +
1.114 +TInt DUBootldrFactory::Install()
1.115 + {
1.116 + return SetName(&KBootldrLddName);
1.117 + }
1.118 +
1.119 +DUBootldrFactory::~DUBootldrFactory()
1.120 + {
1.121 + }
1.122 +
1.123 +void DUBootldrFactory::GetCaps(TDes8& /*aDes*/) const
1.124 + {
1.125 + // Not used but required as DLogicalDevice::GetCaps is pure virtual
1.126 + }
1.127 +
1.128 +TInt DUBootldrFactory::Create(DLogicalChannelBase*& aChannel)
1.129 + {
1.130 + aChannel = NULL;
1.131 + DUBootldrChannel* channel=new DUBootldrChannel;
1.132 + if(!channel)
1.133 + return KErrNoMemory;
1.134 + channel->iFactory = this;
1.135 + aChannel = channel;
1.136 + return KErrNone;
1.137 + }
1.138 +
1.139 +void DUBootldrFactory::LockWait()
1.140 + {
1.141 + NKern::FMWait(&iLock);
1.142 + }
1.143 +
1.144 +void DUBootldrFactory::LockSignal()
1.145 + {
1.146 + NKern::FMSignal(&iLock);
1.147 + }
1.148 +
1.149 +DECLARE_STANDARD_LDD()
1.150 + {
1.151 + return new DUBootldrFactory;
1.152 + }
1.153 +
1.154 +//
1.155 +// DUBootldrChannel
1.156 +//
1.157 +
1.158 +TInt DUBootldrChannel::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& /*aVer*/)
1.159 + {
1.160 + return KErrNone;
1.161 + }
1.162 +
1.163 +DUBootldrChannel::~DUBootldrChannel()
1.164 + {
1.165 + if(iChunk)
1.166 + iChunk->Close(0);
1.167 + }
1.168 +
1.169 +DChunk* DUBootldrChannel::OpenChunk(TLinAddr* aKernelAddr,TInt* aMaxSize)
1.170 + {
1.171 + __ASSERT_CRITICAL // Thread must be in critical section (to avoid leaking access count on chunk)
1.172 + LockWait();
1.173 + DChunk* chunk=iChunk;
1.174 + if(chunk)
1.175 + if(chunk->Open()!=KErrNone)
1.176 + chunk = NULL;
1.177 + if(aKernelAddr)
1.178 + *aKernelAddr = chunk ? iKernelAddress : NULL;
1.179 + if(aMaxSize)
1.180 + *aMaxSize = chunk ? iMaxSize : 0;
1.181 + LockSignal();
1.182 + return chunk;
1.183 + }
1.184 +
1.185 +
1.186 +TUint8 ReadByte(volatile TUint8* aPtr)
1.187 + {
1.188 + return *aPtr;
1.189 + }
1.190 +
1.191 +
1.192 +TInt DUBootldrChannel::Request(TInt aFunction, TAny* a1, TAny* a2)
1.193 + {
1.194 +// Kern::Printf("Request a1 0x%x a2 0x%x", (TUint)a1, (TUint)a2);
1.195 + TInt r=KErrNotSupported;
1.196 +
1.197 + switch(aFunction)
1.198 + {
1.199 +
1.200 + case RUBootldrLdd::ECreateChunk:
1.201 + {
1.202 + if(ChunkDestroyedCount==0)
1.203 + NKern::Sleep(NKern::TimerTicks(100)); // Go idle for a while to let chunk cleanup DFCs to be called
1.204 +
1.205 + NKern::ThreadEnterCS();
1.206 + TInt chunksize = (TInt)a1;
1.207 +
1.208 + TChunkCleanup* cleanup = new TChunkCleanup(this->iFactory,ETrue);
1.209 + if(!cleanup)
1.210 + {
1.211 + NKern::ThreadLeaveCS();
1.212 + return KErrNoMemory;
1.213 + }
1.214 +
1.215 + // Try and create chunk...
1.216 + DChunk* chunk;
1.217 + TChunkCreateInfo info;
1.218 +
1.219 + info.iType=TChunkCreateInfo::ESharedKernelSingle;
1.220 + info.iMaxSize = chunksize;
1.221 + info.iMapAttr = EMapAttrFullyBlocking;
1.222 + info.iOwnsMemory = EFalse;
1.223 + info.iDestroyedDfc = cleanup;
1.224 +
1.225 + TUint32 mapAttr;
1.226 + TUint32 kernAddr;
1.227 + r = Kern::ChunkCreate(info, chunk, kernAddr, mapAttr);
1.228 + if(r!=KErrNone)
1.229 + {
1.230 + delete cleanup;
1.231 + NKern::ThreadLeaveCS();
1.232 + return r;
1.233 + }
1.234 +
1.235 + // Setup data members
1.236 + LockWait();
1.237 + if(iChunk)
1.238 + r = KErrAlreadyExists;
1.239 + else
1.240 + {
1.241 + if(r==KErrNone)
1.242 + {
1.243 + iChunk = chunk;
1.244 + iKernelAddress = kernAddr;
1.245 + iMaxSize = info.iMaxSize;
1.246 + ChunkDestroyedCount = 0;
1.247 + }
1.248 + }
1.249 + LockSignal();
1.250 +
1.251 + if(r!=KErrNone)
1.252 + {
1.253 + // There was an error, so discard created chunk
1.254 + cleanup->Cancel();
1.255 + Kern::ChunkClose(chunk);
1.256 + NKern::ThreadLeaveCS();
1.257 + return r;
1.258 + }
1.259 +
1.260 + NKern::ThreadLeaveCS();
1.261 +
1.262 + // Write back kernel address of chunk
1.263 + if(a2)
1.264 + kumemput32(a2,(TAny*)&kernAddr,4);
1.265 +
1.266 + return KErrNone;
1.267 + }
1.268 +
1.269 +
1.270 + case RUBootldrLdd::EGetChunkHandle:
1.271 + {
1.272 + NKern::ThreadEnterCS();
1.273 + DChunk* chunk=OpenChunk();
1.274 + if(chunk)
1.275 + {
1.276 + r = Kern::MakeHandleAndOpen(0,chunk);
1.277 + chunk->Close(0);
1.278 + }
1.279 + else
1.280 + r = KErrNotFound;
1.281 + NKern::ThreadLeaveCS();
1.282 + return r;
1.283 + }
1.284 +
1.285 +
1.286 + case RUBootldrLdd::ECloseChunkHandle:
1.287 + {
1.288 + NKern::ThreadEnterCS();
1.289 + r = Kern::CloseHandle(0,(TInt)a1);
1.290 + NKern::ThreadLeaveCS();
1.291 + return r;
1.292 + }
1.293 +
1.294 +
1.295 + case RUBootldrLdd::ECommitMemory:
1.296 + {
1.297 + NKern::ThreadEnterCS();
1.298 + TUint32 chunkKernelAddress;
1.299 + DChunk* chunk=OpenChunk(&chunkKernelAddress);
1.300 + if(chunk)
1.301 + {
1.302 + TUint sz=(TUint)a1;
1.303 + TUint physaddr=(TUint)a2;
1.304 +
1.305 + // Kern::Printf("Commit chunk = 0x%x sz = 0x%x, addr = 0x%x", chunk, sz, physaddr); // XXX
1.306 +
1.307 + // LDD i/f guarantees page alignment of physaddr
1.308 + r = Kern::ChunkCommitPhysical(chunk,0,sz,physaddr);
1.309 + // chunk->Close(0);
1.310 + }
1.311 + else
1.312 + r = KErrNotFound;
1.313 + NKern::ThreadLeaveCS();
1.314 + return r;
1.315 + }
1.316 +
1.317 +
1.318 + case RUBootldrLdd::EIsDestroyed:
1.319 + {
1.320 + // First wait for short while to allow idle thread to run and do
1.321 + // cleanup of chunk
1.322 + NKern::Sleep(NKern::TimerTicks(100));
1.323 + return ChunkDestroyedCount;
1.324 + }
1.325 +
1.326 +
1.327 + case RUBootldrLdd::ECloseChunk:
1.328 + {
1.329 + NKern::ThreadEnterCS();
1.330 +
1.331 + // Claim ownership of the chunk
1.332 + LockWait();
1.333 + DChunk* chunk=iChunk;
1.334 + iChunk = 0;
1.335 + LockSignal();
1.336 +
1.337 + // Close the chunk
1.338 + if(chunk)
1.339 + r = Kern::ChunkClose(chunk);
1.340 + else
1.341 + r = KErrNotFound;
1.342 +
1.343 + NKern::ThreadLeaveCS();
1.344 + return r;
1.345 + }
1.346 + case RUBootldrLdd::ERestart:
1.347 + {
1.348 + TInt aReason = (TInt)a1;
1.349 + // Kern::Printf("Restart:: %d", aReason);
1.350 + Kern::Restart(aReason);
1.351 + return KErrNone; // Notreached
1.352 + }
1.353 + default:
1.354 + return KErrNotSupported;
1.355 + }
1.356 + }