os/kernelhwsrv/kernel/eka/include/memmodel/epoc/mmubase/demand_paging.h
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of the License "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 // e32\include\memmodel\epoc\mmubase\demand_paging.h
    15 // 
    16 //
    17 
    18 #include <ramcache.h>
    19 #include <memmodel.h>
    20 
    21 #ifdef _DEBUG
    22 #define __CONCURRENT_PAGING_INSTRUMENTATION__
    23 #endif
    24 
    25 class DDemandPagingLock;
    26 
    27 /**
    28 Maximum number of paging devices supported.
    29 @internalComponent
    30 */
    31 const TInt KMaxPagingDevices = 1 + KMaxLocalDrives;
    32 
    33 /**
    34 Multiplier for number of request objects in pool per drive that supports code paging.
    35 @internalComponent
    36 */
    37 const TInt KPagingRequestsPerDevice = 2;
    38 
    39 /**
    40 Maximum number of paging request objects supported.
    41 @internalComponent
    42 */
    43 const TInt KMaxPagingRequests = KMaxPagingDevices * KPagingRequestsPerDevice;
    44 
    45 /**
    46 Base class for the demand paging object.
    47 
    48 The main functionality provided by this is:
    49 - Management of the live page list.
    50 - Interface to paging devices (media drivers).
    51 
    52 The 'live page list' contains those pages which are currently present or 'paged in'.
    53 This is a doubly linked list of SPageInfo objects which each represent a page of physical RAM.
    54 
    55 The list is split into two parts; 'young' pages (iYoungList) which are marked as accessible
    56 by the MMU and 'old' pages (iOldList) which are which are not marked as accessible.
    57 The page at the head of iYoungList is the 'youngest' page, and that at the tail
    58 of iOldList is the 'oldest' page.
    59 
    60 This arrangement enables a pseudo Most Recently Used (MRU) algorithm to be implemented
    61 where access to an old page will cause a data abort and the fault handler will then
    62 move this page to the head of the 'young' list; the last young page will then be made
    63 the first old page.
    64 
    65 When a data abort occurs because of an access to a page which is not live, then
    66 a new RAM page is obtained from the systems free pool, this is then filled with the
    67 correct data and added to the start of the live page list. (It is made the 'youngest'
    68 page.) If there are no RAM pages left in the systems free pool, or the live page list is
    69 at its maximum size, (iMinimumPageCount), then the oldest page from the live page list
    70 is recycled and used for the new page.
    71 
    72 If the OS requests RAM pages from the systems free pool and there are not enough then
    73 pages are removed from the live page list to satisfy this request - as long as this does
    74 not make the live page list smaller than the limit specified by iMinimumPageCount.
    75 
    76 @internalComponent
    77 */
    78 class DemandPaging : public RamCacheBase
    79 	{
    80 public:
    81 	/**
    82 	Fault enumeration
    83 	*/
    84 	enum TFault
    85 		{
    86 		EInitialiseFailed = 0,		/**< Error occured during initialisation */
    87 		EInitialiseBadArgs = 1,		/**< Arguments used during initialisation were bad */
    88 		ERamPageLocked = 2,			/**< A page in the live page list was found to be locked */
    89 		EUnexpectedPageType = 3,	/**< A page in the live page list had an unexpected type (SPageInfo::Attribs) */
    90 		EPageInFailed = 4,			/**< An error occured whilst reading data for a 'page in' operation */
    91 		ELockTwice = 5,				/**< DDemandPagingLock::Lock was used twice without an intervening DDemandPagingLock::Unlock. */
    92 		ELockTooBig = 6,			/**< DDemandPagingLock::Lock was used with a size greater than that reserved with DDemandPagingLock::Alloc. */
    93 		EInvalidPagingDevice = 7,	/**< Raised by InstallPagingDevice when the diven device is found to have invalid parameters */
    94 		EDeviceAlreadyExists = 8,	/**< Atempt to install a paging device when one already exists for the ROM or the specified drive. */
    95 		EDeviceMissing = 9,			/**< A Paging Fault occured and the device required to service it was found to be missing. */
    96 		EPageFaultWhilstFMHeld = 10,/**< A Paging Fault occured whilst the current thread held a fast mutex. */
    97 		EPageFreeContiguousPages = 11,/**< An error occured when finding pages to free to make contiguous memory blocks.*/
    98 		};
    99 
   100 	class DPagingRequest;
   101 
   102 	//
   103 	// Configuration and initialisation...
   104 	//
   105 
   106 	/**
   107 	Tests whether rom paging has been requested.
   108 	*/
   109 	static TBool RomPagingRequested();
   110 
   111 	/**
   112 	Tests whether code paging has been requested.
   113 	*/
   114 	static TBool CodePagingRequested();
   115 
   116 	static DemandPaging* New();
   117 	
   118 	DemandPaging();
   119 
   120 	virtual ~DemandPaging();
   121 
   122 	/**
   123 	Intialisation called during MmuBase:Init2.
   124 	*/
   125 	virtual void Init2();
   126 
   127 	/**
   128 	Intialisation called from M::DemandPagingInit.
   129 	*/
   130 	virtual TInt Init3();
   131 
   132 	//
   133 	// Live list management...
   134 	//
   135 
   136 	/**
   137 	Called by a thread whenever it takes an exception.
   138 
   139 	If this function returns KErrNone then the thread will continue execution at the
   140 	instruction which caused the exception. Any other return value will cause the normal
   141 	thread exception handling to continue.
   142 
   143 	The implementation of this function should determine if the exception was casued
   144 	by access to pagable memory, if it wasn't then it should return KErrUnknown.
   145 
   146 	Otherwise it should perform the actions necessary to make the memory accessible
   147 	and return KErrNone. The implementation should also call the threads
   148 	iPagingExcTrap->PagingException
   149 	*/
   150 	virtual TInt Fault(TAny* aExceptionInfo)=0;
   151 
   152 	/**
   153 	Make a page in the live page list not accessible. (By changing it's page table entries.)
   154 
   155 	@pre System Lock held
   156 	@post System Lock held (but may have been released by this function)
   157 	*/
   158 	virtual void SetOld(SPageInfo* aPageInfo)=0;
   159 
   160 	/**
   161 	Make a page in the live page list free to use for other purposes.
   162 	I.e. Unmap it from all of the page tables which map it flush the cache.
   163 
   164 	@pre RamAlloc mutex held
   165 	@pre System Lock held
   166 	@post System Lock held (but may have been released by this function)
   167 	*/
   168 	virtual void SetFree(SPageInfo* aPageInfo)=0;
   169 
   170 	/**
   171 	If the number of young pages excedes that specified by iYoungOldRatio then a
   172 	single page is made 'old'. Call this after adding a new 'young' page.
   173 
   174 	@pre System Lock held
   175 	@post System Lock left unchanged.
   176 	*/
   177 	void BalanceAges();
   178 
   179 	/**
   180 	Add a page to the head of the live page list. I.e. make it the 'youngest' page.
   181 
   182 	@pre System Lock held
   183 	@post System Lock left unchanged.
   184 	*/
   185 	void AddAsYoungest(SPageInfo* aPageInfo);
   186 
   187 	/**
   188 	Mark a page as usused (EPagedFree) and add it to the end of the live page list.
   189 	I.e. make it the 'oldest' page, so that it is the first page to be reused.
   190 
   191 	@pre System Lock held
   192 	@post System Lock left unchanged.
   193 	*/
   194 	void AddAsFreePage(SPageInfo* aPageInfo);
   195 
   196 	/**
   197 	Remove a page from live page list.
   198 	It is set to the state EStatePagedDead.
   199 
   200 	@pre System Lock held
   201 	@post System Lock left unchanged.
   202 	*/
   203 	void RemovePage(SPageInfo* aPageInfo);
   204 
   205 	/**
   206 	Remove the oldest page from the live page list.
   207 	The returned page is no longer mapped by any page table and is marked as unused.
   208 
   209 	@pre System Lock held
   210 	@post System Lock left unchanged.
   211 	*/
   212 	SPageInfo* GetOldestPage();
   213 
   214 	/**
   215 	Remove pages from the live page list and return them to the system's free pool. (Free them.)
   216 
   217 	@param	aNumPages The number of pages to free up.
   218 	@return	True if all pages could be freed, false otherwise
   219 	@pre	RamAlloc mutex held.
   220 	*/
   221 	TBool GetFreePages(TInt aNumPages);
   222 
   223 	/**
   224 	Give a RAM cache page to the paging system for managing.
   225 	This page of RAM may be reused for any purpose.
   226 	If the page has already been donated then no action is taken.
   227 
   228 	@param aPageInfo The page info for the donated page.
   229 
   230 	@see ReclaimRamCachePage.
   231 
   232 	@pre System Lock held
   233 	@post System Lock left unchanged.
   234 	*/
   235 	void DonateRamCachePage(SPageInfo* aPageInfo);
   236 
   237 	/**
   238 	Attempt to reclaim a RAM cache page given to the paging system with #DonateRamCachePage.
   239 	If the RAM page has not been reused for other purposes then the page is
   240 	removed from the paging system's management.
   241 	If the page has not previousely been donated then no action is taken.
   242 
   243 	@param aPageInfo The page info for the page to reclaim.
   244 
   245 	@return True if page successfully reclaimed, false otherwise.
   246 
   247 	@pre System Lock held
   248 	@post System Lock left unchanged.
   249 	*/
   250 	TBool ReclaimRamCachePage(SPageInfo* aPageInfo);
   251 
   252 
   253 	/**
   254 	Check whether the specified page can be discarded by the RAM cache.
   255 
   256 	@param aPageInfo The page info of the page being queried.
   257 	@return ETrue when the page can be discarded, EFalse otherwise.
   258 	@pre System lock held.
   259 	@post System lock held.
   260 	*/
   261 	TBool IsPageDiscardable(SPageInfo& aPageInfo);
   262 
   263 	/**
   264 	Discard the specified page.
   265 	Should only be called on a page if a previous call to IsPageDiscardable()
   266 	returned ETrue and the system lock hasn't been released between the calls.
   267 	The cache will not be reduced beyond the minimum size as a new page will 
   268 	be allocated if necessary.
   269 	
   270 	@param aPageInfo The page info of the page to be discarded
   271 	@param aBlockZoneId The ID of the RAM zone that shouldn't be allocated into.
   272 	@param aBlockRest Set to ETrue to stop allocation as soon as aBlockedZoneId is reached 
   273 	in preference ordering.  EFalse otherwise.
   274 	@return ETrue if the page could be discarded, EFalse otherwise.
   275 	
   276 	@pre System lock held.
   277 	@post System lock held.
   278 	*/
   279 	TBool DoDiscardPage(SPageInfo& aPageInfo, TUint aBlockedZoneId, TBool aBlockRest);
   280 
   281 	/**
   282 	First stage in discarding a list of pages.
   283 
   284 	Must ensure that the pages will still be discardable even if system lock 
   285 	is released after this method has completed.
   286 	To be used in conjunction with DemandPaging::DoDiscardPages1().
   287 
   288 	@param aPageList A NULL terminated list of the pages to be discarded
   289 	@return KErrNone on success.
   290 
   291 	@pre System lock held
   292 	@post System lock held
   293 	*/
   294 	TInt DoDiscardPages0(SPageInfo** aPageList);
   295 
   296 
   297 	/**
   298 	Final stage in discarding a list of page
   299 	Finish discarding the pages previously removed by DemandPaging::DoDiscardPages0().
   300 
   301 	@param aPageList A NULL terminated list of the pages to be discarded
   302 	@return KErrNone on success.
   303 
   304 	@pre System lock held
   305 	@post System lock held
   306 	*/
   307 	TInt DoDiscardPages1(SPageInfo** aPageList);
   308 
   309 	/**
   310 	Get a RAM page for use by a new page to be added to the live page list.
   311 	This tries to obtain a RAM page from the following places:
   312 	1. An unused page in the live page list.
   313 	2. The systems free pool.
   314 	3. The oldest page from the live page list.
   315 
   316     @pre Calling thread must be in a critical section.
   317 	@pre System Lock held
   318 	@post System Lock held
   319 	*/
   320 	SPageInfo* AllocateNewPage();
   321 
   322 	/**
   323 	Move an old page the new youngest page. I.e. move it the the head of the live page list
   324 	and use the MMU to mark it accessible.
   325 	*/
   326 	void Rejuvenate(SPageInfo* aPageInfo);
   327 
   328 	/**
   329 	Reserve one page for locking.
   330 	Increments the reserved page count. May increse the size of the live list, and the minimum and
   331 	maximum page counts.  To unreserve a page, simply decrement the reserved page count.
   332 	@return Whether the operation was sucessful.
   333 	*/
   334 	TBool ReservePage();
   335 
   336 	/**
   337 	Ensure all pages in the given region are present and 'lock' them so that they will not
   338 	be paged out.
   339 	To enable the pages to be paged out again, call UnlockRegion.
   340 	@param aProcess The process to which the linear addresses refer, or NULL for global memory
   341 	@pre Paging mutex held
   342 	*/
   343 	TInt LockRegion(TLinAddr aStart,TInt aSize,DProcess* aProcess);
   344 
   345 	/**
   346 	Mark in all pages in the given region as no longer locked.
   347 	@param aProcess The process to which the linear addresses refer, or NULL for global memory
   348 	This reverses the action of LockRegion.
   349 	*/
   350 	TInt UnlockRegion(TLinAddr aStart,TInt aSize,DProcess* aProcess);
   351 
   352 	/**
   353 	Flush (unmap) all memory which is demand paged.
   354 	This reduces the live page list to a minimum.
   355 	*/
   356 	void FlushAll();
   357 
   358 	/**
   359 	Page in the specified pages and 'lock' it so it will not be paged out.
   360 	To enable the page to be paged out again, call UnlockPage.
   361 	@param aPage The linear address of the page to be locked.
   362 	@param aProcess The process which the page is mapped in.
   363 	@param aPhysAddr The physical address of the page which was locked.
   364 	@pre System Lock held
   365 	@post System Lock held (but may have been released by this function)
   366 	*/
   367 	TInt LockPage(TLinAddr aPage, DProcess* aProcess, TPhysAddr& aPhysAddr);
   368 
   369 	/**
   370 	Mark the specified page as no longer locked.
   371 	This reverses the action of LockPage.
   372 	@param aPage The linear address of the page to be unlocked.
   373 	@param aProcess The process which the page is mapped in.
   374 	@param aPhysAddr The physical address of the page which was originally locked. (Or KPhysAddrInvalid.)
   375 	@pre System Lock held
   376 	@post System Lock held
   377 	*/
   378 	TInt UnlockPage(TLinAddr aPage, DProcess* aProcess, TPhysAddr aPhysAddr);
   379 
   380 	/**
   381 	Implementation of DDemandPagingLock::Alloc
   382 	*/
   383 	TInt ReserveAlloc(TInt aSize, DDemandPagingLock& aLock);
   384 
   385 	/**
   386 	Implementation of DDemandPagingLock::Free
   387 	*/
   388 	void ReserveFree(DDemandPagingLock& aLock);
   389 
   390 	/**
   391 	Implementation of DDemandPagingLock::Lock
   392 	*/
   393 	TBool ReserveLock(DThread* aThread, TLinAddr aStart, TInt aSize, DDemandPagingLock& aLock);
   394 
   395 	/**
   396 	Implementation of DDemandPagingLock::Unlock
   397 	*/
   398 	void ReserveUnlock(DDemandPagingLock& aLock);
   399 
   400 	/**
   401 	Ensure a page is present, paging it in if necessary.  Used in the implementation of LockPage.
   402 	@param aPage    The linear address of the page.
   403 	@param aProcess The process the page is mapped in.
   404 	*/
   405 	virtual TInt EnsurePagePresent(TLinAddr aPage, DProcess* aProcess)=0;
   406 
   407 	/**
   408 	Get the physical address of a page.  Used in the implementation of LockPage and UnlockPage.
   409 	@param aPage    The linear address of the page.
   410 	@param aProcess The process the page is mapped in.
   411 	*/
   412 	virtual TPhysAddr LinearToPhysical(TLinAddr aPage, DProcess* aProcess)=0;
   413 
   414 	/**
   415 	Install the specified paging device.
   416 	@param aDevice The device.
   417 	@return KErrNone or standard error code.
   418 	@post The devices DPagingDevice::iDeviceId has been set.
   419 	*/
   420 	TInt InstallPagingDevice(DPagingDevice* aDevice);
   421 
   422 	/**
   423 	Pure virutal function to allocate the virtual address space for temporary page mapping, for a
   424 	paging request object.  This is called by DoInstallPagingDevice after the object is created.
   425 	@param aReq   The paging request object
   426 	@param aReqId An small integer unique to the supplied paging request object
   427 	*/
   428 	virtual void AllocLoadAddress(DPagingRequest& aReq, TInt aReqId)=0;
   429 
   430 	/**
   431 	Notify the paging system that a page of physical RAM that was used for demand paging is no
   432 	longer mapped into any processes and is about to be freed.  This is called on the multiple
   433 	memory model when a code segment is unloaded.  It is not implemented on the moving memory model.
   434 	*/
   435 	virtual void NotifyPageFree(TPhysAddr aPage)=0;
   436 
   437 	/**
   438 	Called when a realtime thread takes a paging fault.
   439 	Checks whether it's ok for the thread to take to fault.
   440 	@return KErrNone if the paging fault should be further processed
   441 	*/
   442 	TInt CheckRealtimeThreadFault(DThread* aThread, TAny* aContext);
   443 
   444 	/**
   445 	Memory-model specific method to indicate if an address range might contain paged memory.
   446 
   447 	Implementations may return false positives but not false negatives - in other words this method
   448 	may say the range contains paged memory when it does not, but not the other way around.
   449 
   450 	This is used when pinning to determine whether memory could actally be paged.
   451 	*/
   452 	virtual TBool MayBePaged(TLinAddr aStartAddr, TUint aLength);
   453 
   454 public:
   455 	TUint iMinimumPageCount;	/**< Minimum size for the live page list, including locked pages */
   456 	TUint iMaximumPageCount;	/**< Maximum size for the live page list, including locked pages */
   457 	TUint16 iYoungOldRatio;		/**< Ratio of young to old pages in the live page list */
   458 	SDblQue iYoungList;			/**< Head of 'young' page list. */
   459 	TUint iYoungCount;			/**< Number of young pages */
   460 	SDblQue iOldList;			/**< Head of 'old' page list. */
   461 	TUint iOldCount;			/**< Number of young pages */
   462 	TUint iReservePageCount;	/**< Number of pages reserved for locking */
   463 	TUint iMinimumPageLimit;	/**< Minimum size for iMinimumPageCount, not including locked pages.
   464 								     iMinimumPageCount >= iMinimumPageLimit + iReservePageCount */
   465 	
   466 	TLinAddr iTempPages;		/**< Uncached memory location in kernel memory which may be used
   467 									 to map RAM pages whilst they are being paged in. */
   468 
   469 	static DemandPaging* ThePager;	/**< Pointer to the single instance of this class */
   470 
   471 	TUint iInitMinimumPageCount;	/**< Initial value for iMinimumPageCount */
   472 	TUint iInitMaximumPageCount;	/**< Initial value for iMaximumPageCount  */
   473 
   474 	TLinAddr iRomLinearBase;		/**< Linear address of ROM start. */
   475 	TUint iRomSize;					/**< ROM size in bytes. */
   476 	TLinAddr iRomPagedLinearBase;	/**< Linear address for the start of pagable ROM. */
   477 	TUint iRomPagedSize;			/**< The size of pagable ROM in bytes.
   478 										 (Zero indicates ROM is not pagable.) */
   479 	SRomPageInfo* iRomPageIndex;	/**< Pointer to ROM page index. */
   480 
   481 	TLinAddr iCodeLinearBase;		/**< Linear adderss of start of user code area. */
   482 	TUint iCodeSize;				/**< Size of user code area in bytes. */
   483 
   484 public:
   485 	//
   486 	// Paging device management...
   487 	//	
   488 	
   489 	/**
   490 	Information for a paging device.
   491 	*/
   492 	struct SPagingDevice
   493 		{
   494 		TBool			iInstalled;	/**< True, if this device has been installed. */
   495 		DPagingDevice*	iDevice;	/**< Pointer to device object */
   496 		};
   497 
   498 	TInt DoInstallPagingDevice(DPagingDevice* aDevice, TInt aId);
   499 	TInt ReadRomPage(const DPagingRequest* aReq, TLinAddr aRomAddress);
   500 	TInt ReadCodePage(const DPagingRequest* aReq, DMmuCodeSegMemory* aCodeSegMemory, TLinAddr aCodeAddress);
   501 	TInt Decompress(TInt aCompressionType,TLinAddr aDst,TLinAddr aSrc,TUint aSrcSize);
   502 
   503 	inline SPagingDevice& RomPagingDevice()
   504 		{ return iPagingDevices[0]; }
   505 
   506 	inline SPagingDevice& CodePagingDevice(TInt aLocalDriveNumber)
   507 		{ return iPagingDevices[aLocalDriveNumber + 1]; }
   508 
   509 public:
   510 	SPagingDevice iPagingDevices[KMaxPagingDevices];	/**< Array of paging devices. The first device is used for ROM paging. */
   511 	DChunk* iDeviceBuffersChunk;	/**< Shared Chunk used to contain buffers for paging devices */
   512 	TLinAddr iDeviceBuffers;		/**< Address for start of iDeviceBuffersChunk */
   513 	TUint iDeviceBufferSize;		/**< Size of each individual buffer within iDeviceBuffers */
   514 
   515 public:
   516 	//
   517 	// Paging request management...
   518 	//
   519 
   520 	/**
   521 	Resources needed to service a paging request.
   522 	*/
   523 	class DPagingRequest : public SDblQueLink
   524 		{
   525 	public:
   526 		~DPagingRequest();
   527 	public:
   528 		TThreadMessage	iMessage;	/**< Used by the media driver to queue requests */
   529  		DMutex*			iMutex;		/**< A mutex for synchronisation and priority inheritance. */
   530 		TInt			iUsageCount;/**< How many threads are using or waiting for this object. */
   531 		TLinAddr		iBuffer;	/**< A two-page buffer to read compressed data into. */
   532 		TLinAddr		iLoadAddr;	/**< Virtual address to map page at while it's being loaded. */
   533 		TPte*			iLoadPte;	/**< PTE corresponding to iLoadAddr. */
   534 		};
   535 
   536 	/**
   537 	Creates a new DPagingRequest object and adds it to the list and free pool.
   538 	Called from DoInstallPagingDevice.
   539 	*/
   540 	TInt CreateRequestObject();
   541 
   542 	/**
   543 	Get a paging request object, waiting if necessary for one to become available.
   544 	@pre The system lock must be held.
   545 	*/
   546 	DPagingRequest* AcquireRequestObject();
   547 
   548 	/**
   549 	Release a previously acquired paging request object.
   550 	@pre The system lock must be held.
   551 	*/
   552 	void ReleaseRequestObject(DPagingRequest* aReq);
   553 
   554 public:
   555 	/** Count of number of paging requests created. */
   556 	TUint iPagingRequestCount;
   557 
   558 	/** Array of paging request objects. */
   559 	DPagingRequest* iPagingRequests[KMaxPagingRequests];
   560 
   561 	/** Pool of unused paging request objects. */
   562 	SDblQue iFreeRequestPool;
   563 
   564 	/**
   565 	Count of number of paging requests created or currently being created.  Used to allocate request
   566 	object IDs and communicate eventual paging request count to ResizeLiveList.
   567 	*/ 
   568 	TInt iNextPagingRequestCount;
   569 
   570 
   571 public:
   572 	//
   573 	// Test and debug...
   574 	//
   575 
   576 	/**
   577 	Resize the live page list.
   578 	*/
   579 	TInt ResizeLiveList(TUint aMinimumPageCount,TUint aMaximumPageCount);
   580 
   581 	/**
   582 	Return state information about a page of memory ad the given address in the current process.
   583 	*/
   584 	virtual TInt PageState(TLinAddr aAddr)=0;
   585 
   586 	/**
   587 	Debug check to see if current thread can safely acquire the PagingMutex.
   588 	Use this check in locations where paged memory may be accessed. It will detect code which
   589 	would fault if paged memory were accessed.
   590 	@return The held mutex that prohibits acquiring the PagingMutex, or NULL.
   591 	*/
   592 	DMutex* CheckMutexOrder();
   593 
   594 	/**
   595 	Memory-model specific method to indicate if a read from an address range requires a mutex order
   596 	check.  Used in the implementation of CheckMutexOrder.
   597 	*/
   598 	virtual TBool NeedsMutexOrderCheck(TLinAddr aStartAddr, TUint aLength)=0;
   599 
   600 	/**
   601 	Fault the system.
   602 	*/
   603 	static void Panic(TFault aFault);
   604 
   605 private:
   606 
   607 	/**
   608 	Non-cryptographically secure linear congruential pseudo random number generator -
   609 	developed for speed with the use of a single multiply accumulate instruction.
   610 	Derived from section "7.8 RANDOM NUMBER GENERATION" in ARM System Developer's
   611 	guide.
   612 	*/
   613 	static TUint32 FastPseudoRand()
   614 		{
   615 		// Make sure the seed has been lazily initialised.
   616 		FastPseudoRandomise();
   617 
   618 		TUint32 oldX;
   619 		TUint32 newX;
   620 
   621 		// Keep trying to generate the next value in the pseudo random sequence until we
   622 		// are sure no race has been caused by another thread which has entered the same
   623 		// code.
   624 		do
   625 			{
   626 			oldX = PseudoRandSeed;
   627 			newX = 69069 * oldX + 41; // should compile to a single multiply accumulate instruction under ARM
   628 			}
   629 		while(!__e32_atomic_cas_acq32(&PseudoRandSeed, &oldX, newX));
   630 
   631 		return newX;
   632 		}
   633 
   634 	/**
   635 	Initialises the seed value for the pseudo random number generator.
   636 	*/
   637 	static void FastPseudoRandomise()
   638 		{
   639 		// Create the initial seed value for the pseudo random number generator using
   640 		// the current system time.
   641 		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
   642 			{
   643 			Int64 t = Kern::SystemTime();
   644 			PseudoRandSeed = (TUint32)t ^ (TUint32)(t >> 32); // combine the two words for maximum entropy
   645 			
   646 			PseudoRandInitialised = ETrue;
   647 			}
   648 		}
   649 
   650 public:
   651 #ifdef __SUPPORT_DEMAND_PAGING_EMULATION__
   652 	TInt iOriginalRomPageCount;
   653 	TPhysAddr* iOriginalRomPages;
   654 #endif
   655 
   656 	SVMEventInfo iEventInfo;
   657 
   658 #ifdef __CONCURRENT_PAGING_INSTRUMENTATION__
   659 	TInt iWaitingCount;		///< number of threads waiting to acquire request object
   660 	TInt iPagingCount;		///< number of threads holding request object
   661 	TInt iMaxWaitingCount;  ///< maximum historical value of iWaitingCount
   662 	TInt iMaxPagingCount;	///< maximum historical value of iPagingCount
   663 #endif
   664 	
   665 #ifdef __DEMAND_PAGING_BENCHMARKS__
   666 	void RecordBenchmarkData(TPagingBenchmark aBm, TUint32 aStartTime, TUint32 aEndTime);
   667 	void ResetBenchmarkData(TPagingBenchmark aBm);
   668 	SPagingBenchmarkInfo iBenchmarkInfo[EMaxPagingBm];
   669 #endif
   670 
   671 private:
   672 	static TBool PseudoRandInitialised;	// flag to check whether FastPseudoRand has been lazily initialised yet
   673 	static volatile TUint32 PseudoRandSeed;			// current random seed for FastPseudoRand()
   674 	};
   675 
   676 #ifdef __DEMAND_PAGING_BENCHMARKS__
   677 	
   678 #define START_PAGING_BENCHMARK TUint32 _bmStart = NKern::FastCounter()
   679 #define END_PAGING_BENCHMARK(pager, bm) pager->RecordBenchmarkData(bm, _bmStart, NKern::FastCounter())
   680 
   681 #else
   682 	
   683 #define START_PAGING_BENCHMARK
   684 #define END_PAGING_BENCHMARK(pager, bm)
   685 
   686 #endif