sl@0: // Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of the License "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // e32\include\memmodel\epoc\mmubase\demand_paging.h sl@0: // sl@0: // sl@0: sl@0: #include sl@0: #include sl@0: sl@0: #ifdef _DEBUG sl@0: #define __CONCURRENT_PAGING_INSTRUMENTATION__ sl@0: #endif sl@0: sl@0: class DDemandPagingLock; sl@0: sl@0: /** sl@0: Maximum number of paging devices supported. sl@0: @internalComponent sl@0: */ sl@0: const TInt KMaxPagingDevices = 1 + KMaxLocalDrives; sl@0: sl@0: /** sl@0: Multiplier for number of request objects in pool per drive that supports code paging. sl@0: @internalComponent sl@0: */ sl@0: const TInt KPagingRequestsPerDevice = 2; sl@0: sl@0: /** sl@0: Maximum number of paging request objects supported. sl@0: @internalComponent sl@0: */ sl@0: const TInt KMaxPagingRequests = KMaxPagingDevices * KPagingRequestsPerDevice; sl@0: sl@0: /** sl@0: Base class for the demand paging object. sl@0: sl@0: The main functionality provided by this is: sl@0: - Management of the live page list. sl@0: - Interface to paging devices (media drivers). sl@0: sl@0: The 'live page list' contains those pages which are currently present or 'paged in'. sl@0: This is a doubly linked list of SPageInfo objects which each represent a page of physical RAM. sl@0: sl@0: The list is split into two parts; 'young' pages (iYoungList) which are marked as accessible sl@0: by the MMU and 'old' pages (iOldList) which are which are not marked as accessible. sl@0: The page at the head of iYoungList is the 'youngest' page, and that at the tail sl@0: of iOldList is the 'oldest' page. sl@0: sl@0: This arrangement enables a pseudo Most Recently Used (MRU) algorithm to be implemented sl@0: where access to an old page will cause a data abort and the fault handler will then sl@0: move this page to the head of the 'young' list; the last young page will then be made sl@0: the first old page. sl@0: sl@0: When a data abort occurs because of an access to a page which is not live, then sl@0: a new RAM page is obtained from the systems free pool, this is then filled with the sl@0: correct data and added to the start of the live page list. (It is made the 'youngest' sl@0: page.) If there are no RAM pages left in the systems free pool, or the live page list is sl@0: at its maximum size, (iMinimumPageCount), then the oldest page from the live page list sl@0: is recycled and used for the new page. sl@0: sl@0: If the OS requests RAM pages from the systems free pool and there are not enough then sl@0: pages are removed from the live page list to satisfy this request - as long as this does sl@0: not make the live page list smaller than the limit specified by iMinimumPageCount. sl@0: sl@0: @internalComponent sl@0: */ sl@0: class DemandPaging : public RamCacheBase sl@0: { sl@0: public: sl@0: /** sl@0: Fault enumeration sl@0: */ sl@0: enum TFault sl@0: { sl@0: EInitialiseFailed = 0, /**< Error occured during initialisation */ sl@0: EInitialiseBadArgs = 1, /**< Arguments used during initialisation were bad */ sl@0: ERamPageLocked = 2, /**< A page in the live page list was found to be locked */ sl@0: EUnexpectedPageType = 3, /**< A page in the live page list had an unexpected type (SPageInfo::Attribs) */ sl@0: EPageInFailed = 4, /**< An error occured whilst reading data for a 'page in' operation */ sl@0: ELockTwice = 5, /**< DDemandPagingLock::Lock was used twice without an intervening DDemandPagingLock::Unlock. */ sl@0: ELockTooBig = 6, /**< DDemandPagingLock::Lock was used with a size greater than that reserved with DDemandPagingLock::Alloc. */ sl@0: EInvalidPagingDevice = 7, /**< Raised by InstallPagingDevice when the diven device is found to have invalid parameters */ sl@0: EDeviceAlreadyExists = 8, /**< Atempt to install a paging device when one already exists for the ROM or the specified drive. */ sl@0: EDeviceMissing = 9, /**< A Paging Fault occured and the device required to service it was found to be missing. */ sl@0: EPageFaultWhilstFMHeld = 10,/**< A Paging Fault occured whilst the current thread held a fast mutex. */ sl@0: EPageFreeContiguousPages = 11,/**< An error occured when finding pages to free to make contiguous memory blocks.*/ sl@0: }; sl@0: sl@0: class DPagingRequest; sl@0: sl@0: // sl@0: // Configuration and initialisation... sl@0: // sl@0: sl@0: /** sl@0: Tests whether rom paging has been requested. sl@0: */ sl@0: static TBool RomPagingRequested(); sl@0: sl@0: /** sl@0: Tests whether code paging has been requested. sl@0: */ sl@0: static TBool CodePagingRequested(); sl@0: sl@0: static DemandPaging* New(); sl@0: sl@0: DemandPaging(); sl@0: sl@0: virtual ~DemandPaging(); sl@0: sl@0: /** sl@0: Intialisation called during MmuBase:Init2. sl@0: */ sl@0: virtual void Init2(); sl@0: sl@0: /** sl@0: Intialisation called from M::DemandPagingInit. sl@0: */ sl@0: virtual TInt Init3(); sl@0: sl@0: // sl@0: // Live list management... sl@0: // sl@0: sl@0: /** sl@0: Called by a thread whenever it takes an exception. sl@0: sl@0: If this function returns KErrNone then the thread will continue execution at the sl@0: instruction which caused the exception. Any other return value will cause the normal sl@0: thread exception handling to continue. sl@0: sl@0: The implementation of this function should determine if the exception was casued sl@0: by access to pagable memory, if it wasn't then it should return KErrUnknown. sl@0: sl@0: Otherwise it should perform the actions necessary to make the memory accessible sl@0: and return KErrNone. The implementation should also call the threads sl@0: iPagingExcTrap->PagingException sl@0: */ sl@0: virtual TInt Fault(TAny* aExceptionInfo)=0; sl@0: sl@0: /** sl@0: Make a page in the live page list not accessible. (By changing it's page table entries.) sl@0: sl@0: @pre System Lock held sl@0: @post System Lock held (but may have been released by this function) sl@0: */ sl@0: virtual void SetOld(SPageInfo* aPageInfo)=0; sl@0: sl@0: /** sl@0: Make a page in the live page list free to use for other purposes. sl@0: I.e. Unmap it from all of the page tables which map it flush the cache. sl@0: sl@0: @pre RamAlloc mutex held sl@0: @pre System Lock held sl@0: @post System Lock held (but may have been released by this function) sl@0: */ sl@0: virtual void SetFree(SPageInfo* aPageInfo)=0; sl@0: sl@0: /** sl@0: If the number of young pages excedes that specified by iYoungOldRatio then a sl@0: single page is made 'old'. Call this after adding a new 'young' page. sl@0: sl@0: @pre System Lock held sl@0: @post System Lock left unchanged. sl@0: */ sl@0: void BalanceAges(); sl@0: sl@0: /** sl@0: Add a page to the head of the live page list. I.e. make it the 'youngest' page. sl@0: sl@0: @pre System Lock held sl@0: @post System Lock left unchanged. sl@0: */ sl@0: void AddAsYoungest(SPageInfo* aPageInfo); sl@0: sl@0: /** sl@0: Mark a page as usused (EPagedFree) and add it to the end of the live page list. sl@0: I.e. make it the 'oldest' page, so that it is the first page to be reused. sl@0: sl@0: @pre System Lock held sl@0: @post System Lock left unchanged. sl@0: */ sl@0: void AddAsFreePage(SPageInfo* aPageInfo); sl@0: sl@0: /** sl@0: Remove a page from live page list. sl@0: It is set to the state EStatePagedDead. sl@0: sl@0: @pre System Lock held sl@0: @post System Lock left unchanged. sl@0: */ sl@0: void RemovePage(SPageInfo* aPageInfo); sl@0: sl@0: /** sl@0: Remove the oldest page from the live page list. sl@0: The returned page is no longer mapped by any page table and is marked as unused. sl@0: sl@0: @pre System Lock held sl@0: @post System Lock left unchanged. sl@0: */ sl@0: SPageInfo* GetOldestPage(); sl@0: sl@0: /** sl@0: Remove pages from the live page list and return them to the system's free pool. (Free them.) sl@0: sl@0: @param aNumPages The number of pages to free up. sl@0: @return True if all pages could be freed, false otherwise sl@0: @pre RamAlloc mutex held. sl@0: */ sl@0: TBool GetFreePages(TInt aNumPages); sl@0: sl@0: /** sl@0: Give a RAM cache page to the paging system for managing. sl@0: This page of RAM may be reused for any purpose. sl@0: If the page has already been donated then no action is taken. sl@0: sl@0: @param aPageInfo The page info for the donated page. sl@0: sl@0: @see ReclaimRamCachePage. sl@0: sl@0: @pre System Lock held sl@0: @post System Lock left unchanged. sl@0: */ sl@0: void DonateRamCachePage(SPageInfo* aPageInfo); sl@0: sl@0: /** sl@0: Attempt to reclaim a RAM cache page given to the paging system with #DonateRamCachePage. sl@0: If the RAM page has not been reused for other purposes then the page is sl@0: removed from the paging system's management. sl@0: If the page has not previousely been donated then no action is taken. sl@0: sl@0: @param aPageInfo The page info for the page to reclaim. sl@0: sl@0: @return True if page successfully reclaimed, false otherwise. sl@0: sl@0: @pre System Lock held sl@0: @post System Lock left unchanged. sl@0: */ sl@0: TBool ReclaimRamCachePage(SPageInfo* aPageInfo); sl@0: sl@0: sl@0: /** sl@0: Check whether the specified page can be discarded by the RAM cache. sl@0: sl@0: @param aPageInfo The page info of the page being queried. sl@0: @return ETrue when the page can be discarded, EFalse otherwise. sl@0: @pre System lock held. sl@0: @post System lock held. sl@0: */ sl@0: TBool IsPageDiscardable(SPageInfo& aPageInfo); sl@0: sl@0: /** sl@0: Discard the specified page. sl@0: Should only be called on a page if a previous call to IsPageDiscardable() sl@0: returned ETrue and the system lock hasn't been released between the calls. sl@0: The cache will not be reduced beyond the minimum size as a new page will sl@0: be allocated if necessary. sl@0: sl@0: @param aPageInfo The page info of the page to be discarded sl@0: @param aBlockZoneId The ID of the RAM zone that shouldn't be allocated into. sl@0: @param aBlockRest Set to ETrue to stop allocation as soon as aBlockedZoneId is reached sl@0: in preference ordering. EFalse otherwise. sl@0: @return ETrue if the page could be discarded, EFalse otherwise. sl@0: sl@0: @pre System lock held. sl@0: @post System lock held. sl@0: */ sl@0: TBool DoDiscardPage(SPageInfo& aPageInfo, TUint aBlockedZoneId, TBool aBlockRest); sl@0: sl@0: /** sl@0: First stage in discarding a list of pages. sl@0: sl@0: Must ensure that the pages will still be discardable even if system lock sl@0: is released after this method has completed. sl@0: To be used in conjunction with DemandPaging::DoDiscardPages1(). sl@0: sl@0: @param aPageList A NULL terminated list of the pages to be discarded sl@0: @return KErrNone on success. sl@0: sl@0: @pre System lock held sl@0: @post System lock held sl@0: */ sl@0: TInt DoDiscardPages0(SPageInfo** aPageList); sl@0: sl@0: sl@0: /** sl@0: Final stage in discarding a list of page sl@0: Finish discarding the pages previously removed by DemandPaging::DoDiscardPages0(). sl@0: sl@0: @param aPageList A NULL terminated list of the pages to be discarded sl@0: @return KErrNone on success. sl@0: sl@0: @pre System lock held sl@0: @post System lock held sl@0: */ sl@0: TInt DoDiscardPages1(SPageInfo** aPageList); sl@0: sl@0: /** sl@0: Get a RAM page for use by a new page to be added to the live page list. sl@0: This tries to obtain a RAM page from the following places: sl@0: 1. An unused page in the live page list. sl@0: 2. The systems free pool. sl@0: 3. The oldest page from the live page list. sl@0: sl@0: @pre Calling thread must be in a critical section. sl@0: @pre System Lock held sl@0: @post System Lock held sl@0: */ sl@0: SPageInfo* AllocateNewPage(); sl@0: sl@0: /** sl@0: Move an old page the new youngest page. I.e. move it the the head of the live page list sl@0: and use the MMU to mark it accessible. sl@0: */ sl@0: void Rejuvenate(SPageInfo* aPageInfo); sl@0: sl@0: /** sl@0: Reserve one page for locking. sl@0: Increments the reserved page count. May increse the size of the live list, and the minimum and sl@0: maximum page counts. To unreserve a page, simply decrement the reserved page count. sl@0: @return Whether the operation was sucessful. sl@0: */ sl@0: TBool ReservePage(); sl@0: sl@0: /** sl@0: Ensure all pages in the given region are present and 'lock' them so that they will not sl@0: be paged out. sl@0: To enable the pages to be paged out again, call UnlockRegion. sl@0: @param aProcess The process to which the linear addresses refer, or NULL for global memory sl@0: @pre Paging mutex held sl@0: */ sl@0: TInt LockRegion(TLinAddr aStart,TInt aSize,DProcess* aProcess); sl@0: sl@0: /** sl@0: Mark in all pages in the given region as no longer locked. sl@0: @param aProcess The process to which the linear addresses refer, or NULL for global memory sl@0: This reverses the action of LockRegion. sl@0: */ sl@0: TInt UnlockRegion(TLinAddr aStart,TInt aSize,DProcess* aProcess); sl@0: sl@0: /** sl@0: Flush (unmap) all memory which is demand paged. sl@0: This reduces the live page list to a minimum. sl@0: */ sl@0: void FlushAll(); sl@0: sl@0: /** sl@0: Page in the specified pages and 'lock' it so it will not be paged out. sl@0: To enable the page to be paged out again, call UnlockPage. sl@0: @param aPage The linear address of the page to be locked. sl@0: @param aProcess The process which the page is mapped in. sl@0: @param aPhysAddr The physical address of the page which was locked. sl@0: @pre System Lock held sl@0: @post System Lock held (but may have been released by this function) sl@0: */ sl@0: TInt LockPage(TLinAddr aPage, DProcess* aProcess, TPhysAddr& aPhysAddr); sl@0: sl@0: /** sl@0: Mark the specified page as no longer locked. sl@0: This reverses the action of LockPage. sl@0: @param aPage The linear address of the page to be unlocked. sl@0: @param aProcess The process which the page is mapped in. sl@0: @param aPhysAddr The physical address of the page which was originally locked. (Or KPhysAddrInvalid.) sl@0: @pre System Lock held sl@0: @post System Lock held sl@0: */ sl@0: TInt UnlockPage(TLinAddr aPage, DProcess* aProcess, TPhysAddr aPhysAddr); sl@0: sl@0: /** sl@0: Implementation of DDemandPagingLock::Alloc sl@0: */ sl@0: TInt ReserveAlloc(TInt aSize, DDemandPagingLock& aLock); sl@0: sl@0: /** sl@0: Implementation of DDemandPagingLock::Free sl@0: */ sl@0: void ReserveFree(DDemandPagingLock& aLock); sl@0: sl@0: /** sl@0: Implementation of DDemandPagingLock::Lock sl@0: */ sl@0: TBool ReserveLock(DThread* aThread, TLinAddr aStart, TInt aSize, DDemandPagingLock& aLock); sl@0: sl@0: /** sl@0: Implementation of DDemandPagingLock::Unlock sl@0: */ sl@0: void ReserveUnlock(DDemandPagingLock& aLock); sl@0: sl@0: /** sl@0: Ensure a page is present, paging it in if necessary. Used in the implementation of LockPage. sl@0: @param aPage The linear address of the page. sl@0: @param aProcess The process the page is mapped in. sl@0: */ sl@0: virtual TInt EnsurePagePresent(TLinAddr aPage, DProcess* aProcess)=0; sl@0: sl@0: /** sl@0: Get the physical address of a page. Used in the implementation of LockPage and UnlockPage. sl@0: @param aPage The linear address of the page. sl@0: @param aProcess The process the page is mapped in. sl@0: */ sl@0: virtual TPhysAddr LinearToPhysical(TLinAddr aPage, DProcess* aProcess)=0; sl@0: sl@0: /** sl@0: Install the specified paging device. sl@0: @param aDevice The device. sl@0: @return KErrNone or standard error code. sl@0: @post The devices DPagingDevice::iDeviceId has been set. sl@0: */ sl@0: TInt InstallPagingDevice(DPagingDevice* aDevice); sl@0: sl@0: /** sl@0: Pure virutal function to allocate the virtual address space for temporary page mapping, for a sl@0: paging request object. This is called by DoInstallPagingDevice after the object is created. sl@0: @param aReq The paging request object sl@0: @param aReqId An small integer unique to the supplied paging request object sl@0: */ sl@0: virtual void AllocLoadAddress(DPagingRequest& aReq, TInt aReqId)=0; sl@0: sl@0: /** sl@0: Notify the paging system that a page of physical RAM that was used for demand paging is no sl@0: longer mapped into any processes and is about to be freed. This is called on the multiple sl@0: memory model when a code segment is unloaded. It is not implemented on the moving memory model. sl@0: */ sl@0: virtual void NotifyPageFree(TPhysAddr aPage)=0; sl@0: sl@0: /** sl@0: Called when a realtime thread takes a paging fault. sl@0: Checks whether it's ok for the thread to take to fault. sl@0: @return KErrNone if the paging fault should be further processed sl@0: */ sl@0: TInt CheckRealtimeThreadFault(DThread* aThread, TAny* aContext); sl@0: sl@0: /** sl@0: Memory-model specific method to indicate if an address range might contain paged memory. sl@0: sl@0: Implementations may return false positives but not false negatives - in other words this method sl@0: may say the range contains paged memory when it does not, but not the other way around. sl@0: sl@0: This is used when pinning to determine whether memory could actally be paged. sl@0: */ sl@0: virtual TBool MayBePaged(TLinAddr aStartAddr, TUint aLength); sl@0: sl@0: public: sl@0: TUint iMinimumPageCount; /**< Minimum size for the live page list, including locked pages */ sl@0: TUint iMaximumPageCount; /**< Maximum size for the live page list, including locked pages */ sl@0: TUint16 iYoungOldRatio; /**< Ratio of young to old pages in the live page list */ sl@0: SDblQue iYoungList; /**< Head of 'young' page list. */ sl@0: TUint iYoungCount; /**< Number of young pages */ sl@0: SDblQue iOldList; /**< Head of 'old' page list. */ sl@0: TUint iOldCount; /**< Number of young pages */ sl@0: TUint iReservePageCount; /**< Number of pages reserved for locking */ sl@0: TUint iMinimumPageLimit; /**< Minimum size for iMinimumPageCount, not including locked pages. sl@0: iMinimumPageCount >= iMinimumPageLimit + iReservePageCount */ sl@0: sl@0: TLinAddr iTempPages; /**< Uncached memory location in kernel memory which may be used sl@0: to map RAM pages whilst they are being paged in. */ sl@0: sl@0: static DemandPaging* ThePager; /**< Pointer to the single instance of this class */ sl@0: sl@0: TUint iInitMinimumPageCount; /**< Initial value for iMinimumPageCount */ sl@0: TUint iInitMaximumPageCount; /**< Initial value for iMaximumPageCount */ sl@0: sl@0: TLinAddr iRomLinearBase; /**< Linear address of ROM start. */ sl@0: TUint iRomSize; /**< ROM size in bytes. */ sl@0: TLinAddr iRomPagedLinearBase; /**< Linear address for the start of pagable ROM. */ sl@0: TUint iRomPagedSize; /**< The size of pagable ROM in bytes. sl@0: (Zero indicates ROM is not pagable.) */ sl@0: SRomPageInfo* iRomPageIndex; /**< Pointer to ROM page index. */ sl@0: sl@0: TLinAddr iCodeLinearBase; /**< Linear adderss of start of user code area. */ sl@0: TUint iCodeSize; /**< Size of user code area in bytes. */ sl@0: sl@0: public: sl@0: // sl@0: // Paging device management... sl@0: // sl@0: sl@0: /** sl@0: Information for a paging device. sl@0: */ sl@0: struct SPagingDevice sl@0: { sl@0: TBool iInstalled; /**< True, if this device has been installed. */ sl@0: DPagingDevice* iDevice; /**< Pointer to device object */ sl@0: }; sl@0: sl@0: TInt DoInstallPagingDevice(DPagingDevice* aDevice, TInt aId); sl@0: TInt ReadRomPage(const DPagingRequest* aReq, TLinAddr aRomAddress); sl@0: TInt ReadCodePage(const DPagingRequest* aReq, DMmuCodeSegMemory* aCodeSegMemory, TLinAddr aCodeAddress); sl@0: TInt Decompress(TInt aCompressionType,TLinAddr aDst,TLinAddr aSrc,TUint aSrcSize); sl@0: sl@0: inline SPagingDevice& RomPagingDevice() sl@0: { return iPagingDevices[0]; } sl@0: sl@0: inline SPagingDevice& CodePagingDevice(TInt aLocalDriveNumber) sl@0: { return iPagingDevices[aLocalDriveNumber + 1]; } sl@0: sl@0: public: sl@0: SPagingDevice iPagingDevices[KMaxPagingDevices]; /**< Array of paging devices. The first device is used for ROM paging. */ sl@0: DChunk* iDeviceBuffersChunk; /**< Shared Chunk used to contain buffers for paging devices */ sl@0: TLinAddr iDeviceBuffers; /**< Address for start of iDeviceBuffersChunk */ sl@0: TUint iDeviceBufferSize; /**< Size of each individual buffer within iDeviceBuffers */ sl@0: sl@0: public: sl@0: // sl@0: // Paging request management... sl@0: // sl@0: sl@0: /** sl@0: Resources needed to service a paging request. sl@0: */ sl@0: class DPagingRequest : public SDblQueLink sl@0: { sl@0: public: sl@0: ~DPagingRequest(); sl@0: public: sl@0: TThreadMessage iMessage; /**< Used by the media driver to queue requests */ sl@0: DMutex* iMutex; /**< A mutex for synchronisation and priority inheritance. */ sl@0: TInt iUsageCount;/**< How many threads are using or waiting for this object. */ sl@0: TLinAddr iBuffer; /**< A two-page buffer to read compressed data into. */ sl@0: TLinAddr iLoadAddr; /**< Virtual address to map page at while it's being loaded. */ sl@0: TPte* iLoadPte; /**< PTE corresponding to iLoadAddr. */ sl@0: }; sl@0: sl@0: /** sl@0: Creates a new DPagingRequest object and adds it to the list and free pool. sl@0: Called from DoInstallPagingDevice. sl@0: */ sl@0: TInt CreateRequestObject(); sl@0: sl@0: /** sl@0: Get a paging request object, waiting if necessary for one to become available. sl@0: @pre The system lock must be held. sl@0: */ sl@0: DPagingRequest* AcquireRequestObject(); sl@0: sl@0: /** sl@0: Release a previously acquired paging request object. sl@0: @pre The system lock must be held. sl@0: */ sl@0: void ReleaseRequestObject(DPagingRequest* aReq); sl@0: sl@0: public: sl@0: /** Count of number of paging requests created. */ sl@0: TUint iPagingRequestCount; sl@0: sl@0: /** Array of paging request objects. */ sl@0: DPagingRequest* iPagingRequests[KMaxPagingRequests]; sl@0: sl@0: /** Pool of unused paging request objects. */ sl@0: SDblQue iFreeRequestPool; sl@0: sl@0: /** sl@0: Count of number of paging requests created or currently being created. Used to allocate request sl@0: object IDs and communicate eventual paging request count to ResizeLiveList. sl@0: */ sl@0: TInt iNextPagingRequestCount; sl@0: sl@0: sl@0: public: sl@0: // sl@0: // Test and debug... sl@0: // sl@0: sl@0: /** sl@0: Resize the live page list. sl@0: */ sl@0: TInt ResizeLiveList(TUint aMinimumPageCount,TUint aMaximumPageCount); sl@0: sl@0: /** sl@0: Return state information about a page of memory ad the given address in the current process. sl@0: */ sl@0: virtual TInt PageState(TLinAddr aAddr)=0; sl@0: sl@0: /** sl@0: Debug check to see if current thread can safely acquire the PagingMutex. sl@0: Use this check in locations where paged memory may be accessed. It will detect code which sl@0: would fault if paged memory were accessed. sl@0: @return The held mutex that prohibits acquiring the PagingMutex, or NULL. sl@0: */ sl@0: DMutex* CheckMutexOrder(); sl@0: sl@0: /** sl@0: Memory-model specific method to indicate if a read from an address range requires a mutex order sl@0: check. Used in the implementation of CheckMutexOrder. sl@0: */ sl@0: virtual TBool NeedsMutexOrderCheck(TLinAddr aStartAddr, TUint aLength)=0; sl@0: sl@0: /** sl@0: Fault the system. sl@0: */ sl@0: static void Panic(TFault aFault); sl@0: sl@0: private: sl@0: sl@0: /** sl@0: Non-cryptographically secure linear congruential pseudo random number generator - sl@0: developed for speed with the use of a single multiply accumulate instruction. sl@0: Derived from section "7.8 RANDOM NUMBER GENERATION" in ARM System Developer's sl@0: guide. sl@0: */ sl@0: static TUint32 FastPseudoRand() sl@0: { sl@0: // Make sure the seed has been lazily initialised. sl@0: FastPseudoRandomise(); sl@0: sl@0: TUint32 oldX; sl@0: TUint32 newX; sl@0: sl@0: // Keep trying to generate the next value in the pseudo random sequence until we sl@0: // are sure no race has been caused by another thread which has entered the same sl@0: // code. sl@0: do sl@0: { sl@0: oldX = PseudoRandSeed; sl@0: newX = 69069 * oldX + 41; // should compile to a single multiply accumulate instruction under ARM sl@0: } sl@0: while(!__e32_atomic_cas_acq32(&PseudoRandSeed, &oldX, newX)); sl@0: sl@0: return newX; sl@0: } sl@0: sl@0: /** sl@0: Initialises the seed value for the pseudo random number generator. sl@0: */ sl@0: static void FastPseudoRandomise() sl@0: { sl@0: // Create the initial seed value for the pseudo random number generator using sl@0: // the current system time. sl@0: 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 sl@0: { sl@0: Int64 t = Kern::SystemTime(); sl@0: PseudoRandSeed = (TUint32)t ^ (TUint32)(t >> 32); // combine the two words for maximum entropy sl@0: sl@0: PseudoRandInitialised = ETrue; sl@0: } sl@0: } sl@0: sl@0: public: sl@0: #ifdef __SUPPORT_DEMAND_PAGING_EMULATION__ sl@0: TInt iOriginalRomPageCount; sl@0: TPhysAddr* iOriginalRomPages; sl@0: #endif sl@0: sl@0: SVMEventInfo iEventInfo; sl@0: sl@0: #ifdef __CONCURRENT_PAGING_INSTRUMENTATION__ sl@0: TInt iWaitingCount; ///< number of threads waiting to acquire request object sl@0: TInt iPagingCount; ///< number of threads holding request object sl@0: TInt iMaxWaitingCount; ///< maximum historical value of iWaitingCount sl@0: TInt iMaxPagingCount; ///< maximum historical value of iPagingCount sl@0: #endif sl@0: sl@0: #ifdef __DEMAND_PAGING_BENCHMARKS__ sl@0: void RecordBenchmarkData(TPagingBenchmark aBm, TUint32 aStartTime, TUint32 aEndTime); sl@0: void ResetBenchmarkData(TPagingBenchmark aBm); sl@0: SPagingBenchmarkInfo iBenchmarkInfo[EMaxPagingBm]; sl@0: #endif sl@0: sl@0: private: sl@0: static TBool PseudoRandInitialised; // flag to check whether FastPseudoRand has been lazily initialised yet sl@0: static volatile TUint32 PseudoRandSeed; // current random seed for FastPseudoRand() sl@0: }; sl@0: sl@0: #ifdef __DEMAND_PAGING_BENCHMARKS__ sl@0: sl@0: #define START_PAGING_BENCHMARK TUint32 _bmStart = NKern::FastCounter() sl@0: #define END_PAGING_BENCHMARK(pager, bm) pager->RecordBenchmarkData(bm, _bmStart, NKern::FastCounter()) sl@0: sl@0: #else sl@0: sl@0: #define START_PAGING_BENCHMARK sl@0: #define END_PAGING_BENCHMARK(pager, bm) sl@0: sl@0: #endif