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