1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/kernel/eka/memmodel/epoc/flexible/mmu/mcodepaging.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,418 @@
1.4 +// Copyright (c) 2008-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 <plat_priv.h>
1.20 +#include "cache_maintenance.h"
1.21 +#include "mm.h"
1.22 +#include "mmu.h"
1.23 +#include "mmanager.h"
1.24 +#include "mobject.h"
1.25 +#include "mpager.h"
1.26 +#include "mcodepaging.h"
1.27 +
1.28 +/**
1.29 +Manager for memory objects containing demand paged executable code.
1.30 +This is the memory used by DCodeSegMemory object to store the contents of RAM loaded
1.31 +EXEs and DLLs which are to be demand paged.
1.32 +
1.33 +This memory has associated information, supplied by the Loader, which enables
1.34 +the executable's code to be located in the file system and its contents
1.35 +relocated and fixed-up when demand loaded.
1.36 +
1.37 +@see DPagedCodeInfo
1.38 +@see MM::PagedCodeNew
1.39 +*/
1.40 +class DCodePagedMemoryManager : public DPagedMemoryManager
1.41 + {
1.42 +private:
1.43 + // from DMemoryManager...
1.44 + virtual TInt New(DMemoryObject*& aMemory, TUint aSizeInPages, TMemoryAttributes aAttributes, TMemoryCreateFlags aCreateFlags);
1.45 + virtual void Destruct(DMemoryObject* aMemory);
1.46 + virtual void Free(DMemoryObject* aMemory, TUint aIndex, TUint aCount);
1.47 + virtual TInt CleanPage(DMemoryObject* aMemory, SPageInfo* aPageInfo, TPhysAddr*& aPageArrayEntry);
1.48 +
1.49 + // from DPagedMemoryManager...
1.50 + virtual void Init3();
1.51 + virtual TInt InstallPagingDevice(DPagingDevice* aDevice);
1.52 + virtual TInt AcquirePageReadRequest(DPageReadRequest*& aRequest, DMemoryObject* aMemory, TUint aIndex, TUint aCount);
1.53 + virtual TInt ReadPages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TPhysAddr* aPages, DPageReadRequest* aRequest);
1.54 + virtual TBool IsAllocated(DMemoryObject* aMemory, TUint aIndex, TUint aCount);
1.55 +
1.56 +private:
1.57 + /**
1.58 + Array of paging devices used for each media drive.
1.59 + This is a initialised by #InstallPagingDevice.
1.60 + Drives without paging devices have the null pointer in their entry.
1.61 + */
1.62 + DPagingDevice* iDevice[KMaxLocalDrives];
1.63 +
1.64 +public:
1.65 + /**
1.66 + The single instance of this manager class.
1.67 + */
1.68 + static DCodePagedMemoryManager TheManager;
1.69 +
1.70 + friend DPagingDevice* CodePagingDevice(TInt aDiveNum);
1.71 + };
1.72 +
1.73 +
1.74 +/**
1.75 +Reference counted object containing a #TPagedCodeInfo.
1.76 +This is a structure containing the information about a demand paged code segment
1.77 +which is required to load and fixup its code section.
1.78 +
1.79 +An instance of this object is created for each memory object being managed by
1.80 +#DCodePagedMemoryManager, and a pointer to it is stored in the memory object's
1.81 +DMemoryObject::iManagerData member.
1.82 +
1.83 +@see TPagedCodeInfo
1.84 +@see MM::PagedCodeLoaded
1.85 +*/
1.86 +class DPagedCodeInfo : public DReferenceCountedObject
1.87 + {
1.88 +public:
1.89 + /**
1.90 + Return a reference to the embedded #TPagedCodeInfo.
1.91 + */
1.92 + inline TPagedCodeInfo& Info()
1.93 + { return iInfo; }
1.94 +private:
1.95 + /**
1.96 + @copybrief TPagedCodeInfo
1.97 + */
1.98 + TPagedCodeInfo iInfo;
1.99 + };
1.100 +
1.101 +
1.102 +DCodePagedMemoryManager DCodePagedMemoryManager::TheManager;
1.103 +DPagedMemoryManager* TheCodePagedMemoryManager = &DCodePagedMemoryManager::TheManager;
1.104 +
1.105 +
1.106 +DPagingDevice* CodePagingDevice(TInt aDriveNum)
1.107 + {
1.108 + __NK_ASSERT_DEBUG(aDriveNum<KMaxLocalDrives);
1.109 + return DCodePagedMemoryManager::TheManager.iDevice[aDriveNum];
1.110 + }
1.111 +
1.112 +
1.113 +void DCodePagedMemoryManager::Init3()
1.114 + {
1.115 + TRACEB(("DCodePagedMemoryManager::Init3()"));
1.116 + }
1.117 +
1.118 +
1.119 +TInt DCodePagedMemoryManager::InstallPagingDevice(DPagingDevice* aDevice)
1.120 + {
1.121 + TRACEB(("DCodePagedMemoryManager::InstallPagingDevice(0x%08x)",aDevice));
1.122 +
1.123 + TUint codePolicy = TheSuperPage().KernelConfigFlags() & EKernelConfigCodePagingPolicyMask;
1.124 + TRACEB(("Code Paging Policy = %d", codePolicy >> EKernelConfigCodePagingPolicyShift));
1.125 + if(codePolicy == EKernelConfigCodePagingPolicyNoPaging)
1.126 + {
1.127 + // no paging allowed so end now...
1.128 + return KErrNone;
1.129 + }
1.130 +
1.131 + TInt i;
1.132 + for(i=0; i<KMaxLocalDrives; ++i)
1.133 + if(aDevice->iDrivesSupported&(1<<i))
1.134 + {
1.135 + TRACEB(("DCodePagedMemoryManager::InstallPagingDevice drive=%d",i));
1.136 + TAny* null = 0;
1.137 + if(!__e32_atomic_cas_ord_ptr(&iDevice[i], &null, aDevice)) // set iDevice[i]=aDevice if it was originally 0
1.138 + {
1.139 + // paging device already registered...
1.140 + TRACEB(("DCodePagedMemoryManager::InstallPagingDevice returns ALREADY EXISTS!"));
1.141 + return KErrAlreadyExists;
1.142 + }
1.143 + // flag code paging is supported...
1.144 + __e32_atomic_ior_ord32(&K::MemModelAttributes, (TUint32)EMemModelAttrCodePaging);
1.145 + }
1.146 +
1.147 + return KErrNone;
1.148 + }
1.149 +
1.150 +
1.151 +TInt DCodePagedMemoryManager::AcquirePageReadRequest(DPageReadRequest*& aRequest, DMemoryObject* aMemory, TUint aIndex, TUint aCount)
1.152 + {
1.153 + DPagingDevice* device = 0;
1.154 + MmuLock::Lock();
1.155 + DPagedCodeInfo* pagedCodeInfo = (DPagedCodeInfo*)aMemory->iManagerData;
1.156 + if(pagedCodeInfo)
1.157 + {
1.158 + TPagedCodeInfo& info = pagedCodeInfo->Info();
1.159 + device = iDevice[info.iCodeLocalDrive];
1.160 + }
1.161 + MmuLock::Unlock();
1.162 +
1.163 + if(!device)
1.164 + {
1.165 + aRequest = 0;
1.166 + return KErrNotFound;
1.167 + }
1.168 +
1.169 + aRequest = device->iRequestPool->AcquirePageReadRequest(aMemory,aIndex,aCount);
1.170 + return KErrNone;
1.171 + }
1.172 +
1.173 +
1.174 +TInt DCodePagedMemoryManager::New(DMemoryObject*& aMemory, TUint aSizeInPages, TMemoryAttributes aAttributes, TMemoryCreateFlags aCreateFlags)
1.175 + {
1.176 + DPagedCodeInfo* pagedCodeInfo = new DPagedCodeInfo;
1.177 + if(!pagedCodeInfo)
1.178 + return KErrNoMemory;
1.179 +
1.180 + TInt r = DPagedMemoryManager::New(aMemory, aSizeInPages, aAttributes, aCreateFlags);
1.181 + if(r!=KErrNone)
1.182 + pagedCodeInfo->Close();
1.183 + else
1.184 + aMemory->iManagerData = pagedCodeInfo;
1.185 +
1.186 + return r;
1.187 + }
1.188 +
1.189 +
1.190 +void DCodePagedMemoryManager::Destruct(DMemoryObject* aMemory)
1.191 + {
1.192 + MmuLock::Lock();
1.193 + DPagedCodeInfo* pagedCodeInfo = (DPagedCodeInfo*)aMemory->iManagerData;
1.194 + aMemory->iManagerData = 0;
1.195 + MmuLock::Unlock();
1.196 +
1.197 + if(pagedCodeInfo)
1.198 + pagedCodeInfo->Close();
1.199 +
1.200 + // base call to free memory and close object...
1.201 + DPagedMemoryManager::Destruct(aMemory);
1.202 + }
1.203 +
1.204 +
1.205 +void DCodePagedMemoryManager::Free(DMemoryObject* aMemory, TUint aIndex, TUint aCount)
1.206 + {
1.207 + DoFree(aMemory,aIndex,aCount);
1.208 + }
1.209 +
1.210 +
1.211 +TInt DCodePagedMemoryManager::CleanPage(DMemoryObject* aMemory, SPageInfo* aPageInfo, TPhysAddr*& aPageArrayEntry)
1.212 + {
1.213 + if(aPageInfo->IsDirty()==false)
1.214 + return KErrNone;
1.215 +
1.216 + // shouldn't be asked to clean a page which is writable...
1.217 + __NK_ASSERT_DEBUG(aPageInfo->IsWritable()==false);
1.218 +
1.219 + // Note, memory may have been modified by the CodeModifier class.
1.220 +
1.221 + // just mark page as clean as we don't try and preserve code modifications...
1.222 + ThePager.SetClean(*aPageInfo);
1.223 +
1.224 + return KErrNone;
1.225 + }
1.226 +
1.227 +
1.228 +TInt ReadFunc(TAny* aArg1, TAny* aArg2, TLinAddr aBuffer, TInt aBlockNumber, TInt aBlockCount)
1.229 + {
1.230 + START_PAGING_BENCHMARK;
1.231 + TInt drive = (TInt)aArg1;
1.232 + TThreadMessage* msg = (TThreadMessage*)aArg2;
1.233 + DPagingDevice* device = CodePagingDevice(drive);
1.234 + TInt r = device->Read(msg, aBuffer, aBlockNumber, aBlockCount, drive);
1.235 + __NK_ASSERT_DEBUG(r!=KErrNoMemory); // not allowed to allocated memory, therefore can't fail with KErrNoMemory
1.236 + END_PAGING_BENCHMARK(EPagingBmReadMedia);
1.237 + return r;
1.238 + }
1.239 +
1.240 +
1.241 +TInt DCodePagedMemoryManager::ReadPages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TPhysAddr* aPages, DPageReadRequest* aRequest)
1.242 + {
1.243 + TRACE2(("DCodePagedMemoryManager::ReadPage(0x%08x,0x%08x,0x%08x,?,?)",aMemory,aIndex,aCount));
1.244 +
1.245 + __NK_ASSERT_DEBUG(aRequest->CheckUse(aMemory,aIndex,aCount));
1.246 +
1.247 + START_PAGING_BENCHMARK;
1.248 +
1.249 + MmuLock::Lock();
1.250 + DPagedCodeInfo* pagedCodeInfo = (DPagedCodeInfo*)aMemory->iManagerData;
1.251 + if(pagedCodeInfo)
1.252 + pagedCodeInfo->Open();
1.253 + MmuLock::Unlock();
1.254 + if(!pagedCodeInfo)
1.255 + return KErrNotFound;
1.256 +
1.257 + TPagedCodeInfo& info = pagedCodeInfo->Info();
1.258 + DPagingDevice& device = *iDevice[info.iCodeLocalDrive];
1.259 +
1.260 + TLinAddr linAddr = aRequest->MapPages(aIndex,aCount,aPages);
1.261 + TInt r = KErrNone;
1.262 +
1.263 + if(!info.iCodeSize)
1.264 + {
1.265 + // no blockmap yet, use blank pages...
1.266 + memset((TAny*)linAddr, aCount*KPageSize, 0x03);
1.267 + CacheMaintenance::CodeChanged(linAddr, aCount*KPageSize);
1.268 + goto done;
1.269 + }
1.270 +
1.271 + for(; aCount; ++aIndex, --aCount, linAddr+=KPageSize)
1.272 + {
1.273 + // work out which bit of the file to read
1.274 + TInt codeOffset = aIndex<<KPageShift;
1.275 + TInt dataOffset;
1.276 + TInt dataSize;
1.277 + TInt decompressedSize = Min(KPageSize, info.iCodeSize-codeOffset);
1.278 + if(info.iCompressionType)
1.279 + {
1.280 + dataOffset = info.iCodePageOffsets[aIndex];
1.281 + dataSize = info.iCodePageOffsets[aIndex+1] - dataOffset;
1.282 + __KTRACE_OPT(KPAGING,Kern::Printf(" compressed, file offset == %x, size == %d", dataOffset, dataSize));
1.283 + }
1.284 + else
1.285 + {
1.286 + dataOffset = codeOffset + info.iCodeStartInFile;
1.287 + dataSize = Min(KPageSize, info.iBlockMap.DataLength()-dataOffset);
1.288 + __NK_ASSERT_DEBUG(dataSize==decompressedSize);
1.289 + __KTRACE_OPT(KPAGING,Kern::Printf(" uncompressed, file offset == %x, size == %d", dataOffset, dataSize));
1.290 + }
1.291 +
1.292 + TInt bufferStart = info.iBlockMap.Read(aRequest->iBuffer,
1.293 + dataOffset,
1.294 + dataSize,
1.295 + device.iReadUnitShift,
1.296 + ReadFunc,
1.297 + (TAny*)info.iCodeLocalDrive,
1.298 + (TAny*)&aRequest->iMessage);
1.299 +
1.300 + if(bufferStart<0)
1.301 + {
1.302 + r = bufferStart; // return error
1.303 + __NK_ASSERT_DEBUG(0);
1.304 + break;
1.305 + }
1.306 +
1.307 + TLinAddr data = aRequest->iBuffer + bufferStart;
1.308 + r = Decompress(info.iCompressionType, linAddr, decompressedSize, data, dataSize);
1.309 + if(r>=0)
1.310 + {
1.311 + if(r!=decompressedSize)
1.312 + {
1.313 + __KTRACE_OPT(KPANIC, Kern::Printf("DCodePagedMemoryManager::ReadPage: error decompressing page at %08x + %x: %d", dataOffset, dataSize, r));
1.314 + __NK_ASSERT_DEBUG(0);
1.315 + r = KErrCorrupt;
1.316 + }
1.317 + else
1.318 + r = KErrNone;
1.319 + }
1.320 + else
1.321 + {
1.322 + __NK_ASSERT_DEBUG(0);
1.323 + }
1.324 +
1.325 + if(r!=KErrNone)
1.326 + break;
1.327 +
1.328 + if(decompressedSize<KPageSize)
1.329 + memset((TAny*)(linAddr+decompressedSize), KPageSize-decompressedSize, 0x03);
1.330 + if(info.iLoaded)
1.331 + info.ApplyFixups(linAddr, aIndex);
1.332 + }
1.333 +done:
1.334 + aRequest->UnmapPages(true);
1.335 +
1.336 + pagedCodeInfo->AsyncClose();
1.337 +
1.338 + END_PAGING_BENCHMARK(EPagingBmReadCodePage);
1.339 + return r;
1.340 + }
1.341 +
1.342 +
1.343 +TBool DCodePagedMemoryManager::IsAllocated(DMemoryObject* aMemory, TUint aIndex, TUint aCount)
1.344 + {
1.345 + // all pages allocated if memory not destroyed (iManagerData!=0)...
1.346 + return aMemory->iManagerData!=0;
1.347 + }
1.348 +
1.349 +
1.350 +TInt MM::PagedCodeNew(DMemoryObject*& aMemory, TUint aPageCount, TPagedCodeInfo*& aInfo)
1.351 + {
1.352 + TRACE(("MM::PagedCodeNew(?,0x%08x,0x%08x)",aPageCount,aInfo));
1.353 + TMemoryCreateFlags createFlags = (TMemoryCreateFlags)(EMemoryCreateNoWipe | EMemoryCreateAllowExecution);
1.354 + TInt r = TheCodePagedMemoryManager->New(aMemory,aPageCount,EMemoryAttributeStandard,createFlags);
1.355 + if(r==KErrNone)
1.356 + aInfo = &((DPagedCodeInfo*)aMemory->iManagerData)->Info();
1.357 + TRACE(("MM::PagedCodeNew returns %d, aMemory=0x%08x",r,aMemory));
1.358 + return r;
1.359 + }
1.360 +
1.361 +
1.362 +void MM::PagedCodeLoaded(DMemoryObject* aMemory, TLinAddr aLoadAddress)
1.363 + {
1.364 + TRACE(("MM::PagedCodeLoaded(0x%08x,0x%08x)",aMemory,aLoadAddress));
1.365 +
1.366 + TPagedCodeInfo& info = ((DPagedCodeInfo*)aMemory->iManagerData)->Info();
1.367 +
1.368 + // we need to apply fixups for all memory already paged in.
1.369 + // Note, if this memory is subsequently discarded it should not be paged-in again
1.370 + // until after this function has completed, because the Loader won't touch the memory
1.371 + // and it has not yet been mapped into any other process.
1.372 +
1.373 + // make iterator for memory...
1.374 + RPageArray::TIter pageIter;
1.375 + aMemory->iPages.FindStart(0,aMemory->iSizeInPages,pageIter);
1.376 +
1.377 + for(;;)
1.378 + {
1.379 + // find some pages...
1.380 + RPageArray::TIter pageList;
1.381 + TUint n = pageIter.Find(pageList);
1.382 + if(!n)
1.383 + break;
1.384 +
1.385 + // fix up each page found...
1.386 + UNLOCK_USER_MEMORY();
1.387 + do
1.388 + {
1.389 + TUint i = pageList.Index();
1.390 + TLinAddr a = aLoadAddress+i*KPageSize;
1.391 + info.ApplyFixups(a,i);
1.392 + CacheMaintenance::CodeChanged(a, KPageSize);
1.393 + // now we've finished updating the page, mark it as read only and
1.394 + // clean as we don't need to save changes if it is stolen.
1.395 + MmuLock::Lock();
1.396 + TPhysAddr* pages;
1.397 + if(pageList.Pages(pages,1)==1)
1.398 + if(RPageArray::IsPresent(*pages))
1.399 + {// The loader page still has a writable mapping but it won't
1.400 + // touch the page again so this is safe. No use restricting the
1.401 + // page to be read only as if the loader did write to it again
1.402 + // it would just be rejuvenated as writeable and made dirty.
1.403 + SPageInfo& pageInfo = *SPageInfo::FromPhysAddr(*pages);
1.404 + pageInfo.SetReadOnly();
1.405 + ThePager.SetClean(pageInfo);
1.406 + }
1.407 + MmuLock::Unlock();
1.408 +
1.409 + pageList.Skip(1);
1.410 + }
1.411 + while(pageList.Count());
1.412 + LOCK_USER_MEMORY();
1.413 +
1.414 + // move on...
1.415 + pageIter.FindRelease(n);
1.416 + }
1.417 +
1.418 + // done...
1.419 + aMemory->iPages.FindEnd(0,aMemory->iSizeInPages);
1.420 + info.iLoaded = true; // allow ReadPage to start applying fixups when handling page faults
1.421 + }