os/kernelhwsrv/kernel/eka/include/memmodel/epoc/mmubase/demand_paging.h
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/kernelhwsrv/kernel/eka/include/memmodel/epoc/mmubase/demand_paging.h	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,686 @@
     1.4 +// Copyright (c) 1998-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 +// e32\include\memmodel\epoc\mmubase\demand_paging.h
    1.18 +// 
    1.19 +//
    1.20 +
    1.21 +#include <ramcache.h>
    1.22 +#include <memmodel.h>
    1.23 +
    1.24 +#ifdef _DEBUG
    1.25 +#define __CONCURRENT_PAGING_INSTRUMENTATION__
    1.26 +#endif
    1.27 +
    1.28 +class DDemandPagingLock;
    1.29 +
    1.30 +/**
    1.31 +Maximum number of paging devices supported.
    1.32 +@internalComponent
    1.33 +*/
    1.34 +const TInt KMaxPagingDevices = 1 + KMaxLocalDrives;
    1.35 +
    1.36 +/**
    1.37 +Multiplier for number of request objects in pool per drive that supports code paging.
    1.38 +@internalComponent
    1.39 +*/
    1.40 +const TInt KPagingRequestsPerDevice = 2;
    1.41 +
    1.42 +/**
    1.43 +Maximum number of paging request objects supported.
    1.44 +@internalComponent
    1.45 +*/
    1.46 +const TInt KMaxPagingRequests = KMaxPagingDevices * KPagingRequestsPerDevice;
    1.47 +
    1.48 +/**
    1.49 +Base class for the demand paging object.
    1.50 +
    1.51 +The main functionality provided by this is:
    1.52 +- Management of the live page list.
    1.53 +- Interface to paging devices (media drivers).
    1.54 +
    1.55 +The 'live page list' contains those pages which are currently present or 'paged in'.
    1.56 +This is a doubly linked list of SPageInfo objects which each represent a page of physical RAM.
    1.57 +
    1.58 +The list is split into two parts; 'young' pages (iYoungList) which are marked as accessible
    1.59 +by the MMU and 'old' pages (iOldList) which are which are not marked as accessible.
    1.60 +The page at the head of iYoungList is the 'youngest' page, and that at the tail
    1.61 +of iOldList is the 'oldest' page.
    1.62 +
    1.63 +This arrangement enables a pseudo Most Recently Used (MRU) algorithm to be implemented
    1.64 +where access to an old page will cause a data abort and the fault handler will then
    1.65 +move this page to the head of the 'young' list; the last young page will then be made
    1.66 +the first old page.
    1.67 +
    1.68 +When a data abort occurs because of an access to a page which is not live, then
    1.69 +a new RAM page is obtained from the systems free pool, this is then filled with the
    1.70 +correct data and added to the start of the live page list. (It is made the 'youngest'
    1.71 +page.) If there are no RAM pages left in the systems free pool, or the live page list is
    1.72 +at its maximum size, (iMinimumPageCount), then the oldest page from the live page list
    1.73 +is recycled and used for the new page.
    1.74 +
    1.75 +If the OS requests RAM pages from the systems free pool and there are not enough then
    1.76 +pages are removed from the live page list to satisfy this request - as long as this does
    1.77 +not make the live page list smaller than the limit specified by iMinimumPageCount.
    1.78 +
    1.79 +@internalComponent
    1.80 +*/
    1.81 +class DemandPaging : public RamCacheBase
    1.82 +	{
    1.83 +public:
    1.84 +	/**
    1.85 +	Fault enumeration
    1.86 +	*/
    1.87 +	enum TFault
    1.88 +		{
    1.89 +		EInitialiseFailed = 0,		/**< Error occured during initialisation */
    1.90 +		EInitialiseBadArgs = 1,		/**< Arguments used during initialisation were bad */
    1.91 +		ERamPageLocked = 2,			/**< A page in the live page list was found to be locked */
    1.92 +		EUnexpectedPageType = 3,	/**< A page in the live page list had an unexpected type (SPageInfo::Attribs) */
    1.93 +		EPageInFailed = 4,			/**< An error occured whilst reading data for a 'page in' operation */
    1.94 +		ELockTwice = 5,				/**< DDemandPagingLock::Lock was used twice without an intervening DDemandPagingLock::Unlock. */
    1.95 +		ELockTooBig = 6,			/**< DDemandPagingLock::Lock was used with a size greater than that reserved with DDemandPagingLock::Alloc. */
    1.96 +		EInvalidPagingDevice = 7,	/**< Raised by InstallPagingDevice when the diven device is found to have invalid parameters */
    1.97 +		EDeviceAlreadyExists = 8,	/**< Atempt to install a paging device when one already exists for the ROM or the specified drive. */
    1.98 +		EDeviceMissing = 9,			/**< A Paging Fault occured and the device required to service it was found to be missing. */
    1.99 +		EPageFaultWhilstFMHeld = 10,/**< A Paging Fault occured whilst the current thread held a fast mutex. */
   1.100 +		EPageFreeContiguousPages = 11,/**< An error occured when finding pages to free to make contiguous memory blocks.*/
   1.101 +		};
   1.102 +
   1.103 +	class DPagingRequest;
   1.104 +
   1.105 +	//
   1.106 +	// Configuration and initialisation...
   1.107 +	//
   1.108 +
   1.109 +	/**
   1.110 +	Tests whether rom paging has been requested.
   1.111 +	*/
   1.112 +	static TBool RomPagingRequested();
   1.113 +
   1.114 +	/**
   1.115 +	Tests whether code paging has been requested.
   1.116 +	*/
   1.117 +	static TBool CodePagingRequested();
   1.118 +
   1.119 +	static DemandPaging* New();
   1.120 +	
   1.121 +	DemandPaging();
   1.122 +
   1.123 +	virtual ~DemandPaging();
   1.124 +
   1.125 +	/**
   1.126 +	Intialisation called during MmuBase:Init2.
   1.127 +	*/
   1.128 +	virtual void Init2();
   1.129 +
   1.130 +	/**
   1.131 +	Intialisation called from M::DemandPagingInit.
   1.132 +	*/
   1.133 +	virtual TInt Init3();
   1.134 +
   1.135 +	//
   1.136 +	// Live list management...
   1.137 +	//
   1.138 +
   1.139 +	/**
   1.140 +	Called by a thread whenever it takes an exception.
   1.141 +
   1.142 +	If this function returns KErrNone then the thread will continue execution at the
   1.143 +	instruction which caused the exception. Any other return value will cause the normal
   1.144 +	thread exception handling to continue.
   1.145 +
   1.146 +	The implementation of this function should determine if the exception was casued
   1.147 +	by access to pagable memory, if it wasn't then it should return KErrUnknown.
   1.148 +
   1.149 +	Otherwise it should perform the actions necessary to make the memory accessible
   1.150 +	and return KErrNone. The implementation should also call the threads
   1.151 +	iPagingExcTrap->PagingException
   1.152 +	*/
   1.153 +	virtual TInt Fault(TAny* aExceptionInfo)=0;
   1.154 +
   1.155 +	/**
   1.156 +	Make a page in the live page list not accessible. (By changing it's page table entries.)
   1.157 +
   1.158 +	@pre System Lock held
   1.159 +	@post System Lock held (but may have been released by this function)
   1.160 +	*/
   1.161 +	virtual void SetOld(SPageInfo* aPageInfo)=0;
   1.162 +
   1.163 +	/**
   1.164 +	Make a page in the live page list free to use for other purposes.
   1.165 +	I.e. Unmap it from all of the page tables which map it flush the cache.
   1.166 +
   1.167 +	@pre RamAlloc mutex held
   1.168 +	@pre System Lock held
   1.169 +	@post System Lock held (but may have been released by this function)
   1.170 +	*/
   1.171 +	virtual void SetFree(SPageInfo* aPageInfo)=0;
   1.172 +
   1.173 +	/**
   1.174 +	If the number of young pages excedes that specified by iYoungOldRatio then a
   1.175 +	single page is made 'old'. Call this after adding a new 'young' page.
   1.176 +
   1.177 +	@pre System Lock held
   1.178 +	@post System Lock left unchanged.
   1.179 +	*/
   1.180 +	void BalanceAges();
   1.181 +
   1.182 +	/**
   1.183 +	Add a page to the head of the live page list. I.e. make it the 'youngest' page.
   1.184 +
   1.185 +	@pre System Lock held
   1.186 +	@post System Lock left unchanged.
   1.187 +	*/
   1.188 +	void AddAsYoungest(SPageInfo* aPageInfo);
   1.189 +
   1.190 +	/**
   1.191 +	Mark a page as usused (EPagedFree) and add it to the end of the live page list.
   1.192 +	I.e. make it the 'oldest' page, so that it is the first page to be reused.
   1.193 +
   1.194 +	@pre System Lock held
   1.195 +	@post System Lock left unchanged.
   1.196 +	*/
   1.197 +	void AddAsFreePage(SPageInfo* aPageInfo);
   1.198 +
   1.199 +	/**
   1.200 +	Remove a page from live page list.
   1.201 +	It is set to the state EStatePagedDead.
   1.202 +
   1.203 +	@pre System Lock held
   1.204 +	@post System Lock left unchanged.
   1.205 +	*/
   1.206 +	void RemovePage(SPageInfo* aPageInfo);
   1.207 +
   1.208 +	/**
   1.209 +	Remove the oldest page from the live page list.
   1.210 +	The returned page is no longer mapped by any page table and is marked as unused.
   1.211 +
   1.212 +	@pre System Lock held
   1.213 +	@post System Lock left unchanged.
   1.214 +	*/
   1.215 +	SPageInfo* GetOldestPage();
   1.216 +
   1.217 +	/**
   1.218 +	Remove pages from the live page list and return them to the system's free pool. (Free them.)
   1.219 +
   1.220 +	@param	aNumPages The number of pages to free up.
   1.221 +	@return	True if all pages could be freed, false otherwise
   1.222 +	@pre	RamAlloc mutex held.
   1.223 +	*/
   1.224 +	TBool GetFreePages(TInt aNumPages);
   1.225 +
   1.226 +	/**
   1.227 +	Give a RAM cache page to the paging system for managing.
   1.228 +	This page of RAM may be reused for any purpose.
   1.229 +	If the page has already been donated then no action is taken.
   1.230 +
   1.231 +	@param aPageInfo The page info for the donated page.
   1.232 +
   1.233 +	@see ReclaimRamCachePage.
   1.234 +
   1.235 +	@pre System Lock held
   1.236 +	@post System Lock left unchanged.
   1.237 +	*/
   1.238 +	void DonateRamCachePage(SPageInfo* aPageInfo);
   1.239 +
   1.240 +	/**
   1.241 +	Attempt to reclaim a RAM cache page given to the paging system with #DonateRamCachePage.
   1.242 +	If the RAM page has not been reused for other purposes then the page is
   1.243 +	removed from the paging system's management.
   1.244 +	If the page has not previousely been donated then no action is taken.
   1.245 +
   1.246 +	@param aPageInfo The page info for the page to reclaim.
   1.247 +
   1.248 +	@return True if page successfully reclaimed, false otherwise.
   1.249 +
   1.250 +	@pre System Lock held
   1.251 +	@post System Lock left unchanged.
   1.252 +	*/
   1.253 +	TBool ReclaimRamCachePage(SPageInfo* aPageInfo);
   1.254 +
   1.255 +
   1.256 +	/**
   1.257 +	Check whether the specified page can be discarded by the RAM cache.
   1.258 +
   1.259 +	@param aPageInfo The page info of the page being queried.
   1.260 +	@return ETrue when the page can be discarded, EFalse otherwise.
   1.261 +	@pre System lock held.
   1.262 +	@post System lock held.
   1.263 +	*/
   1.264 +	TBool IsPageDiscardable(SPageInfo& aPageInfo);
   1.265 +
   1.266 +	/**
   1.267 +	Discard the specified page.
   1.268 +	Should only be called on a page if a previous call to IsPageDiscardable()
   1.269 +	returned ETrue and the system lock hasn't been released between the calls.
   1.270 +	The cache will not be reduced beyond the minimum size as a new page will 
   1.271 +	be allocated if necessary.
   1.272 +	
   1.273 +	@param aPageInfo The page info of the page to be discarded
   1.274 +	@param aBlockZoneId The ID of the RAM zone that shouldn't be allocated into.
   1.275 +	@param aBlockRest Set to ETrue to stop allocation as soon as aBlockedZoneId is reached 
   1.276 +	in preference ordering.  EFalse otherwise.
   1.277 +	@return ETrue if the page could be discarded, EFalse otherwise.
   1.278 +	
   1.279 +	@pre System lock held.
   1.280 +	@post System lock held.
   1.281 +	*/
   1.282 +	TBool DoDiscardPage(SPageInfo& aPageInfo, TUint aBlockedZoneId, TBool aBlockRest);
   1.283 +
   1.284 +	/**
   1.285 +	First stage in discarding a list of pages.
   1.286 +
   1.287 +	Must ensure that the pages will still be discardable even if system lock 
   1.288 +	is released after this method has completed.
   1.289 +	To be used in conjunction with DemandPaging::DoDiscardPages1().
   1.290 +
   1.291 +	@param aPageList A NULL terminated list of the pages to be discarded
   1.292 +	@return KErrNone on success.
   1.293 +
   1.294 +	@pre System lock held
   1.295 +	@post System lock held
   1.296 +	*/
   1.297 +	TInt DoDiscardPages0(SPageInfo** aPageList);
   1.298 +
   1.299 +
   1.300 +	/**
   1.301 +	Final stage in discarding a list of page
   1.302 +	Finish discarding the pages previously removed by DemandPaging::DoDiscardPages0().
   1.303 +
   1.304 +	@param aPageList A NULL terminated list of the pages to be discarded
   1.305 +	@return KErrNone on success.
   1.306 +
   1.307 +	@pre System lock held
   1.308 +	@post System lock held
   1.309 +	*/
   1.310 +	TInt DoDiscardPages1(SPageInfo** aPageList);
   1.311 +
   1.312 +	/**
   1.313 +	Get a RAM page for use by a new page to be added to the live page list.
   1.314 +	This tries to obtain a RAM page from the following places:
   1.315 +	1. An unused page in the live page list.
   1.316 +	2. The systems free pool.
   1.317 +	3. The oldest page from the live page list.
   1.318 +
   1.319 +    @pre Calling thread must be in a critical section.
   1.320 +	@pre System Lock held
   1.321 +	@post System Lock held
   1.322 +	*/
   1.323 +	SPageInfo* AllocateNewPage();
   1.324 +
   1.325 +	/**
   1.326 +	Move an old page the new youngest page. I.e. move it the the head of the live page list
   1.327 +	and use the MMU to mark it accessible.
   1.328 +	*/
   1.329 +	void Rejuvenate(SPageInfo* aPageInfo);
   1.330 +
   1.331 +	/**
   1.332 +	Reserve one page for locking.
   1.333 +	Increments the reserved page count. May increse the size of the live list, and the minimum and
   1.334 +	maximum page counts.  To unreserve a page, simply decrement the reserved page count.
   1.335 +	@return Whether the operation was sucessful.
   1.336 +	*/
   1.337 +	TBool ReservePage();
   1.338 +
   1.339 +	/**
   1.340 +	Ensure all pages in the given region are present and 'lock' them so that they will not
   1.341 +	be paged out.
   1.342 +	To enable the pages to be paged out again, call UnlockRegion.
   1.343 +	@param aProcess The process to which the linear addresses refer, or NULL for global memory
   1.344 +	@pre Paging mutex held
   1.345 +	*/
   1.346 +	TInt LockRegion(TLinAddr aStart,TInt aSize,DProcess* aProcess);
   1.347 +
   1.348 +	/**
   1.349 +	Mark in all pages in the given region as no longer locked.
   1.350 +	@param aProcess The process to which the linear addresses refer, or NULL for global memory
   1.351 +	This reverses the action of LockRegion.
   1.352 +	*/
   1.353 +	TInt UnlockRegion(TLinAddr aStart,TInt aSize,DProcess* aProcess);
   1.354 +
   1.355 +	/**
   1.356 +	Flush (unmap) all memory which is demand paged.
   1.357 +	This reduces the live page list to a minimum.
   1.358 +	*/
   1.359 +	void FlushAll();
   1.360 +
   1.361 +	/**
   1.362 +	Page in the specified pages and 'lock' it so it will not be paged out.
   1.363 +	To enable the page to be paged out again, call UnlockPage.
   1.364 +	@param aPage The linear address of the page to be locked.
   1.365 +	@param aProcess The process which the page is mapped in.
   1.366 +	@param aPhysAddr The physical address of the page which was locked.
   1.367 +	@pre System Lock held
   1.368 +	@post System Lock held (but may have been released by this function)
   1.369 +	*/
   1.370 +	TInt LockPage(TLinAddr aPage, DProcess* aProcess, TPhysAddr& aPhysAddr);
   1.371 +
   1.372 +	/**
   1.373 +	Mark the specified page as no longer locked.
   1.374 +	This reverses the action of LockPage.
   1.375 +	@param aPage The linear address of the page to be unlocked.
   1.376 +	@param aProcess The process which the page is mapped in.
   1.377 +	@param aPhysAddr The physical address of the page which was originally locked. (Or KPhysAddrInvalid.)
   1.378 +	@pre System Lock held
   1.379 +	@post System Lock held
   1.380 +	*/
   1.381 +	TInt UnlockPage(TLinAddr aPage, DProcess* aProcess, TPhysAddr aPhysAddr);
   1.382 +
   1.383 +	/**
   1.384 +	Implementation of DDemandPagingLock::Alloc
   1.385 +	*/
   1.386 +	TInt ReserveAlloc(TInt aSize, DDemandPagingLock& aLock);
   1.387 +
   1.388 +	/**
   1.389 +	Implementation of DDemandPagingLock::Free
   1.390 +	*/
   1.391 +	void ReserveFree(DDemandPagingLock& aLock);
   1.392 +
   1.393 +	/**
   1.394 +	Implementation of DDemandPagingLock::Lock
   1.395 +	*/
   1.396 +	TBool ReserveLock(DThread* aThread, TLinAddr aStart, TInt aSize, DDemandPagingLock& aLock);
   1.397 +
   1.398 +	/**
   1.399 +	Implementation of DDemandPagingLock::Unlock
   1.400 +	*/
   1.401 +	void ReserveUnlock(DDemandPagingLock& aLock);
   1.402 +
   1.403 +	/**
   1.404 +	Ensure a page is present, paging it in if necessary.  Used in the implementation of LockPage.
   1.405 +	@param aPage    The linear address of the page.
   1.406 +	@param aProcess The process the page is mapped in.
   1.407 +	*/
   1.408 +	virtual TInt EnsurePagePresent(TLinAddr aPage, DProcess* aProcess)=0;
   1.409 +
   1.410 +	/**
   1.411 +	Get the physical address of a page.  Used in the implementation of LockPage and UnlockPage.
   1.412 +	@param aPage    The linear address of the page.
   1.413 +	@param aProcess The process the page is mapped in.
   1.414 +	*/
   1.415 +	virtual TPhysAddr LinearToPhysical(TLinAddr aPage, DProcess* aProcess)=0;
   1.416 +
   1.417 +	/**
   1.418 +	Install the specified paging device.
   1.419 +	@param aDevice The device.
   1.420 +	@return KErrNone or standard error code.
   1.421 +	@post The devices DPagingDevice::iDeviceId has been set.
   1.422 +	*/
   1.423 +	TInt InstallPagingDevice(DPagingDevice* aDevice);
   1.424 +
   1.425 +	/**
   1.426 +	Pure virutal function to allocate the virtual address space for temporary page mapping, for a
   1.427 +	paging request object.  This is called by DoInstallPagingDevice after the object is created.
   1.428 +	@param aReq   The paging request object
   1.429 +	@param aReqId An small integer unique to the supplied paging request object
   1.430 +	*/
   1.431 +	virtual void AllocLoadAddress(DPagingRequest& aReq, TInt aReqId)=0;
   1.432 +
   1.433 +	/**
   1.434 +	Notify the paging system that a page of physical RAM that was used for demand paging is no
   1.435 +	longer mapped into any processes and is about to be freed.  This is called on the multiple
   1.436 +	memory model when a code segment is unloaded.  It is not implemented on the moving memory model.
   1.437 +	*/
   1.438 +	virtual void NotifyPageFree(TPhysAddr aPage)=0;
   1.439 +
   1.440 +	/**
   1.441 +	Called when a realtime thread takes a paging fault.
   1.442 +	Checks whether it's ok for the thread to take to fault.
   1.443 +	@return KErrNone if the paging fault should be further processed
   1.444 +	*/
   1.445 +	TInt CheckRealtimeThreadFault(DThread* aThread, TAny* aContext);
   1.446 +
   1.447 +	/**
   1.448 +	Memory-model specific method to indicate if an address range might contain paged memory.
   1.449 +
   1.450 +	Implementations may return false positives but not false negatives - in other words this method
   1.451 +	may say the range contains paged memory when it does not, but not the other way around.
   1.452 +
   1.453 +	This is used when pinning to determine whether memory could actally be paged.
   1.454 +	*/
   1.455 +	virtual TBool MayBePaged(TLinAddr aStartAddr, TUint aLength);
   1.456 +
   1.457 +public:
   1.458 +	TUint iMinimumPageCount;	/**< Minimum size for the live page list, including locked pages */
   1.459 +	TUint iMaximumPageCount;	/**< Maximum size for the live page list, including locked pages */
   1.460 +	TUint16 iYoungOldRatio;		/**< Ratio of young to old pages in the live page list */
   1.461 +	SDblQue iYoungList;			/**< Head of 'young' page list. */
   1.462 +	TUint iYoungCount;			/**< Number of young pages */
   1.463 +	SDblQue iOldList;			/**< Head of 'old' page list. */
   1.464 +	TUint iOldCount;			/**< Number of young pages */
   1.465 +	TUint iReservePageCount;	/**< Number of pages reserved for locking */
   1.466 +	TUint iMinimumPageLimit;	/**< Minimum size for iMinimumPageCount, not including locked pages.
   1.467 +								     iMinimumPageCount >= iMinimumPageLimit + iReservePageCount */
   1.468 +	
   1.469 +	TLinAddr iTempPages;		/**< Uncached memory location in kernel memory which may be used
   1.470 +									 to map RAM pages whilst they are being paged in. */
   1.471 +
   1.472 +	static DemandPaging* ThePager;	/**< Pointer to the single instance of this class */
   1.473 +
   1.474 +	TUint iInitMinimumPageCount;	/**< Initial value for iMinimumPageCount */
   1.475 +	TUint iInitMaximumPageCount;	/**< Initial value for iMaximumPageCount  */
   1.476 +
   1.477 +	TLinAddr iRomLinearBase;		/**< Linear address of ROM start. */
   1.478 +	TUint iRomSize;					/**< ROM size in bytes. */
   1.479 +	TLinAddr iRomPagedLinearBase;	/**< Linear address for the start of pagable ROM. */
   1.480 +	TUint iRomPagedSize;			/**< The size of pagable ROM in bytes.
   1.481 +										 (Zero indicates ROM is not pagable.) */
   1.482 +	SRomPageInfo* iRomPageIndex;	/**< Pointer to ROM page index. */
   1.483 +
   1.484 +	TLinAddr iCodeLinearBase;		/**< Linear adderss of start of user code area. */
   1.485 +	TUint iCodeSize;				/**< Size of user code area in bytes. */
   1.486 +
   1.487 +public:
   1.488 +	//
   1.489 +	// Paging device management...
   1.490 +	//	
   1.491 +	
   1.492 +	/**
   1.493 +	Information for a paging device.
   1.494 +	*/
   1.495 +	struct SPagingDevice
   1.496 +		{
   1.497 +		TBool			iInstalled;	/**< True, if this device has been installed. */
   1.498 +		DPagingDevice*	iDevice;	/**< Pointer to device object */
   1.499 +		};
   1.500 +
   1.501 +	TInt DoInstallPagingDevice(DPagingDevice* aDevice, TInt aId);
   1.502 +	TInt ReadRomPage(const DPagingRequest* aReq, TLinAddr aRomAddress);
   1.503 +	TInt ReadCodePage(const DPagingRequest* aReq, DMmuCodeSegMemory* aCodeSegMemory, TLinAddr aCodeAddress);
   1.504 +	TInt Decompress(TInt aCompressionType,TLinAddr aDst,TLinAddr aSrc,TUint aSrcSize);
   1.505 +
   1.506 +	inline SPagingDevice& RomPagingDevice()
   1.507 +		{ return iPagingDevices[0]; }
   1.508 +
   1.509 +	inline SPagingDevice& CodePagingDevice(TInt aLocalDriveNumber)
   1.510 +		{ return iPagingDevices[aLocalDriveNumber + 1]; }
   1.511 +
   1.512 +public:
   1.513 +	SPagingDevice iPagingDevices[KMaxPagingDevices];	/**< Array of paging devices. The first device is used for ROM paging. */
   1.514 +	DChunk* iDeviceBuffersChunk;	/**< Shared Chunk used to contain buffers for paging devices */
   1.515 +	TLinAddr iDeviceBuffers;		/**< Address for start of iDeviceBuffersChunk */
   1.516 +	TUint iDeviceBufferSize;		/**< Size of each individual buffer within iDeviceBuffers */
   1.517 +
   1.518 +public:
   1.519 +	//
   1.520 +	// Paging request management...
   1.521 +	//
   1.522 +
   1.523 +	/**
   1.524 +	Resources needed to service a paging request.
   1.525 +	*/
   1.526 +	class DPagingRequest : public SDblQueLink
   1.527 +		{
   1.528 +	public:
   1.529 +		~DPagingRequest();
   1.530 +	public:
   1.531 +		TThreadMessage	iMessage;	/**< Used by the media driver to queue requests */
   1.532 + 		DMutex*			iMutex;		/**< A mutex for synchronisation and priority inheritance. */
   1.533 +		TInt			iUsageCount;/**< How many threads are using or waiting for this object. */
   1.534 +		TLinAddr		iBuffer;	/**< A two-page buffer to read compressed data into. */
   1.535 +		TLinAddr		iLoadAddr;	/**< Virtual address to map page at while it's being loaded. */
   1.536 +		TPte*			iLoadPte;	/**< PTE corresponding to iLoadAddr. */
   1.537 +		};
   1.538 +
   1.539 +	/**
   1.540 +	Creates a new DPagingRequest object and adds it to the list and free pool.
   1.541 +	Called from DoInstallPagingDevice.
   1.542 +	*/
   1.543 +	TInt CreateRequestObject();
   1.544 +
   1.545 +	/**
   1.546 +	Get a paging request object, waiting if necessary for one to become available.
   1.547 +	@pre The system lock must be held.
   1.548 +	*/
   1.549 +	DPagingRequest* AcquireRequestObject();
   1.550 +
   1.551 +	/**
   1.552 +	Release a previously acquired paging request object.
   1.553 +	@pre The system lock must be held.
   1.554 +	*/
   1.555 +	void ReleaseRequestObject(DPagingRequest* aReq);
   1.556 +
   1.557 +public:
   1.558 +	/** Count of number of paging requests created. */
   1.559 +	TUint iPagingRequestCount;
   1.560 +
   1.561 +	/** Array of paging request objects. */
   1.562 +	DPagingRequest* iPagingRequests[KMaxPagingRequests];
   1.563 +
   1.564 +	/** Pool of unused paging request objects. */
   1.565 +	SDblQue iFreeRequestPool;
   1.566 +
   1.567 +	/**
   1.568 +	Count of number of paging requests created or currently being created.  Used to allocate request
   1.569 +	object IDs and communicate eventual paging request count to ResizeLiveList.
   1.570 +	*/ 
   1.571 +	TInt iNextPagingRequestCount;
   1.572 +
   1.573 +
   1.574 +public:
   1.575 +	//
   1.576 +	// Test and debug...
   1.577 +	//
   1.578 +
   1.579 +	/**
   1.580 +	Resize the live page list.
   1.581 +	*/
   1.582 +	TInt ResizeLiveList(TUint aMinimumPageCount,TUint aMaximumPageCount);
   1.583 +
   1.584 +	/**
   1.585 +	Return state information about a page of memory ad the given address in the current process.
   1.586 +	*/
   1.587 +	virtual TInt PageState(TLinAddr aAddr)=0;
   1.588 +
   1.589 +	/**
   1.590 +	Debug check to see if current thread can safely acquire the PagingMutex.
   1.591 +	Use this check in locations where paged memory may be accessed. It will detect code which
   1.592 +	would fault if paged memory were accessed.
   1.593 +	@return The held mutex that prohibits acquiring the PagingMutex, or NULL.
   1.594 +	*/
   1.595 +	DMutex* CheckMutexOrder();
   1.596 +
   1.597 +	/**
   1.598 +	Memory-model specific method to indicate if a read from an address range requires a mutex order
   1.599 +	check.  Used in the implementation of CheckMutexOrder.
   1.600 +	*/
   1.601 +	virtual TBool NeedsMutexOrderCheck(TLinAddr aStartAddr, TUint aLength)=0;
   1.602 +
   1.603 +	/**
   1.604 +	Fault the system.
   1.605 +	*/
   1.606 +	static void Panic(TFault aFault);
   1.607 +
   1.608 +private:
   1.609 +
   1.610 +	/**
   1.611 +	Non-cryptographically secure linear congruential pseudo random number generator -
   1.612 +	developed for speed with the use of a single multiply accumulate instruction.
   1.613 +	Derived from section "7.8 RANDOM NUMBER GENERATION" in ARM System Developer's
   1.614 +	guide.
   1.615 +	*/
   1.616 +	static TUint32 FastPseudoRand()
   1.617 +		{
   1.618 +		// Make sure the seed has been lazily initialised.
   1.619 +		FastPseudoRandomise();
   1.620 +
   1.621 +		TUint32 oldX;
   1.622 +		TUint32 newX;
   1.623 +
   1.624 +		// Keep trying to generate the next value in the pseudo random sequence until we
   1.625 +		// are sure no race has been caused by another thread which has entered the same
   1.626 +		// code.
   1.627 +		do
   1.628 +			{
   1.629 +			oldX = PseudoRandSeed;
   1.630 +			newX = 69069 * oldX + 41; // should compile to a single multiply accumulate instruction under ARM
   1.631 +			}
   1.632 +		while(!__e32_atomic_cas_acq32(&PseudoRandSeed, &oldX, newX));
   1.633 +
   1.634 +		return newX;
   1.635 +		}
   1.636 +
   1.637 +	/**
   1.638 +	Initialises the seed value for the pseudo random number generator.
   1.639 +	*/
   1.640 +	static void FastPseudoRandomise()
   1.641 +		{
   1.642 +		// Create the initial seed value for the pseudo random number generator using
   1.643 +		// the current system time.
   1.644 +		if(!PseudoRandInitialised) // race-prone but harmless - worst that can happen is that the seed is initialised more than once until PseudoRandInitialised is set to true
   1.645 +			{
   1.646 +			Int64 t = Kern::SystemTime();
   1.647 +			PseudoRandSeed = (TUint32)t ^ (TUint32)(t >> 32); // combine the two words for maximum entropy
   1.648 +			
   1.649 +			PseudoRandInitialised = ETrue;
   1.650 +			}
   1.651 +		}
   1.652 +
   1.653 +public:
   1.654 +#ifdef __SUPPORT_DEMAND_PAGING_EMULATION__
   1.655 +	TInt iOriginalRomPageCount;
   1.656 +	TPhysAddr* iOriginalRomPages;
   1.657 +#endif
   1.658 +
   1.659 +	SVMEventInfo iEventInfo;
   1.660 +
   1.661 +#ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
   1.662 +	TInt iWaitingCount;		///< number of threads waiting to acquire request object
   1.663 +	TInt iPagingCount;		///< number of threads holding request object
   1.664 +	TInt iMaxWaitingCount;  ///< maximum historical value of iWaitingCount
   1.665 +	TInt iMaxPagingCount;	///< maximum historical value of iPagingCount
   1.666 +#endif
   1.667 +	
   1.668 +#ifdef __DEMAND_PAGING_BENCHMARKS__
   1.669 +	void RecordBenchmarkData(TPagingBenchmark aBm, TUint32 aStartTime, TUint32 aEndTime);
   1.670 +	void ResetBenchmarkData(TPagingBenchmark aBm);
   1.671 +	SPagingBenchmarkInfo iBenchmarkInfo[EMaxPagingBm];
   1.672 +#endif
   1.673 +
   1.674 +private:
   1.675 +	static TBool PseudoRandInitialised;	// flag to check whether FastPseudoRand has been lazily initialised yet
   1.676 +	static volatile TUint32 PseudoRandSeed;			// current random seed for FastPseudoRand()
   1.677 +	};
   1.678 +
   1.679 +#ifdef __DEMAND_PAGING_BENCHMARKS__
   1.680 +	
   1.681 +#define START_PAGING_BENCHMARK TUint32 _bmStart = NKern::FastCounter()
   1.682 +#define END_PAGING_BENCHMARK(pager, bm) pager->RecordBenchmarkData(bm, _bmStart, NKern::FastCounter())
   1.683 +
   1.684 +#else
   1.685 +	
   1.686 +#define START_PAGING_BENCHMARK
   1.687 +#define END_PAGING_BENCHMARK(pager, bm)
   1.688 +
   1.689 +#endif