os/kernelhwsrv/kernel/eka/memmodel/epoc/flexible/mmu/mpagearray.h
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200 (2012-06-15)
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
sl@0
     1
// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0
     2
// All rights reserved.
sl@0
     3
// This component and the accompanying materials are made available
sl@0
     4
// under the terms of the License "Eclipse Public License v1.0"
sl@0
     5
// which accompanies this distribution, and is available
sl@0
     6
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0
     7
//
sl@0
     8
// Initial Contributors:
sl@0
     9
// Nokia Corporation - initial contribution.
sl@0
    10
//
sl@0
    11
// Contributors:
sl@0
    12
//
sl@0
    13
// Description:
sl@0
    14
//
sl@0
    15
sl@0
    16
#ifndef MPAGEARRAY_H
sl@0
    17
#define MPAGEARRAY_H
sl@0
    18
sl@0
    19
#include "mmu.h"
sl@0
    20
sl@0
    21
const TUint KPageArraySegmentShift = 4;
sl@0
    22
sl@0
    23
/**
sl@0
    24
Number of entries in each segment RPageArray::TSegment.
sl@0
    25
*/
sl@0
    26
const TUint KPageArraySegmentSize = (1<<KPageArraySegmentShift);
sl@0
    27
sl@0
    28
const TUint KPageArraySegmentMask = KPageArraySegmentSize-1;
sl@0
    29
sl@0
    30
/**
sl@0
    31
Bit position in RPageArray::TSegment::iCount for the least significant bit
sl@0
    32
of the 'AllocCount'. I.e. the number of entries which are not empty.
sl@0
    33
*/
sl@0
    34
const TUint KPageArraySegmentAllocCountShift = 31-KPageArraySegmentShift;
sl@0
    35
sl@0
    36
const TUint KPageArraySegmentLockCountMask = (1<<KPageArraySegmentAllocCountShift)-1;
sl@0
    37
sl@0
    38
/**
sl@0
    39
Array which contains the physical addresses of all the pages contained in a DMemoryObject.
sl@0
    40
This is a sparse array, therefore memory storage may not exist for unallocated pages entries.
sl@0
    41
Where storage does exists for unallocated entries, a state value of ENotPresent indicates this.
sl@0
    42
For allocated entries, the redundant least significant bits of each entry contain flags and state
sl@0
    43
from from enum TFlags and TState.
sl@0
    44
sl@0
    45
To add pages to the array:
sl@0
    46
sl@0
    47
@code
sl@0
    48
	RPageArray::TIter iter;
sl@0
    49
	array.AddStart(index,count,iter);
sl@0
    50
		RPageArray::TIter pageList;
sl@0
    51
		while(n = iter.AddFind(pageList))
sl@0
    52
			{
sl@0
    53
			pageList.Add(n,pages);
sl@0
    54
			// or pageList.AddContiguous
sl@0
    55
			}
sl@0
    56
	array.AddEnd(index,count);
sl@0
    57
@endcode
sl@0
    58
sl@0
    59
sl@0
    60
To remove pages from the array:
sl@0
    61
sl@0
    62
@code
sl@0
    63
	RPageArray::TIter iter;
sl@0
    64
	array.FindStart(index,count,iter);
sl@0
    65
		RPageArray::TIter pageList;
sl@0
    66
		while(n = iter.RemoveFind(pageList))
sl@0
    67
			{
sl@0
    68
			pageList.Remove(n,pages);
sl@0
    69
			iter.FindRelease(n);
sl@0
    70
			}
sl@0
    71
	array.FindEnd(index,count);
sl@0
    72
@endcode
sl@0
    73
sl@0
    74
Mutual exclusion must be used to ensure that only a single Add or Remove operation is in
sl@0
    75
progress at any time.
sl@0
    76
sl@0
    77
sl@0
    78
To query the contents of the array:
sl@0
    79
sl@0
    80
@code
sl@0
    81
	RPageArray::TIter iter;
sl@0
    82
	array.FindStart(index,count,iter);
sl@0
    83
		RPageArray::TIter pageList;
sl@0
    84
		while(n=iter.Find(pageList));
sl@0
    85
			{
sl@0
    86
			TPhysAddr* pages;
sl@0
    87
			while(n = pageList.Pages(pages,max))
sl@0
    88
				{
sl@0
    89
				// do something with pages
sl@0
    90
				pageList.Skip(n);
sl@0
    91
				}
sl@0
    92
			iter.FindRelease(n);
sl@0
    93
			}
sl@0
    94
	array.FindEnd(index,count);
sl@0
    95
@endcode
sl@0
    96
sl@0
    97
*/
sl@0
    98
class RPageArray
sl@0
    99
	{
sl@0
   100
public:
sl@0
   101
	class TSegment;
sl@0
   102
	class TIter;
sl@0
   103
sl@0
   104
	/**
sl@0
   105
	States for pages stored in the array. These are stored in least significant part of each entry.
sl@0
   106
	*/
sl@0
   107
	enum TState
sl@0
   108
		{
sl@0
   109
		ENotPresent			= 0x000, ///< No page present.
sl@0
   110
		EDecommitted		= 0x001, ///< Paged Decommitted, but is pinned
sl@0
   111
		EDecommitting		= 0x002, ///< Page is in the process of being decommitted
sl@0
   112
		EStealing			= 0x003, ///< Page is in the process of being stolen
sl@0
   113
		ERestrictingNA		= 0x004, ///< Page is in the process of having no-access restrictions applied
sl@0
   114
		EMoving				= 0x005, ///< Page is in the process of being moved to another physical page
sl@0
   115
		ECommitted			= 0x006, ///< Page is committed
sl@0
   116
sl@0
   117
		EStateShift			= 3,	 ///< Number of bits needed to store state values.
sl@0
   118
		EStateMask			= (1<<EStateShift)-1, ///< Mask for state values
sl@0
   119
sl@0
   120
		EEmptyEntry			= ENotPresent ///< Value of an empty array entry
sl@0
   121
		};
sl@0
   122
sl@0
   123
	/**
sl@0
   124
	Flags stored in array entries in addition to the state.
sl@0
   125
	*/
sl@0
   126
	enum TFlags
sl@0
   127
		{
sl@0
   128
		EUnmapVetoed		= 1<<EStateShift, ///< A Steal or Decommit operation on the page has been vetoed
sl@0
   129
sl@0
   130
		EFlagsShift			= 1,	 ///< Number of bits needed to store flags.
sl@0
   131
		EFlagsMask			= ((1<<EFlagsShift)-1)<<EStateShift ///< Mask for flags values
sl@0
   132
		};
sl@0
   133
sl@0
   134
	/**
sl@0
   135
	Return true if the array entry \a aPage is currently being decommitted.
sl@0
   136
	*/
sl@0
   137
	static FORCE_INLINE TBool TargetStateIsDecommitted(TPhysAddr aPage)
sl@0
   138
		{
sl@0
   139
		return State(aPage)<=EStealing;
sl@0
   140
		}
sl@0
   141
sl@0
   142
	/**
sl@0
   143
	Return true if the array entry \a aPage is currently committed and may be being moved.
sl@0
   144
	*/
sl@0
   145
	static FORCE_INLINE TBool TargetStateIsCommitted(TPhysAddr aPage)
sl@0
   146
		{
sl@0
   147
		__ASSERT_COMPILE(RPageArray::EMoving == RPageArray::ECommitted - 1);
sl@0
   148
		return State(aPage)>=EMoving;
sl@0
   149
		}
sl@0
   150
sl@0
   151
	/**
sl@0
   152
	Return true if the array entry \a aPage is not present.
sl@0
   153
	*/
sl@0
   154
	static FORCE_INLINE TBool IsPresent(TPhysAddr aPage)
sl@0
   155
		{
sl@0
   156
		return State(aPage)!=ENotPresent;
sl@0
   157
		}
sl@0
   158
sl@0
   159
	/**
sl@0
   160
	Return the TState value in the array entry \a aPage.
sl@0
   161
	*/
sl@0
   162
	static FORCE_INLINE TState State(TPhysAddr aPage)
sl@0
   163
		{
sl@0
   164
		return (TState)(aPage&EStateMask);
sl@0
   165
		}
sl@0
   166
sl@0
   167
	/**
sl@0
   168
	Page moving has ended so set the page back to committed if no other 
sl@0
   169
	operation has occurred/is occurring.
sl@0
   170
sl@0
   171
	@param aEntry		A reference to the entry to update.
sl@0
   172
	*/
sl@0
   173
	static FORCE_INLINE void MovePageEnd(TPhysAddr& aEntry)
sl@0
   174
		{
sl@0
   175
		if (State(aEntry) == EMoving)
sl@0
   176
			aEntry = (aEntry & ~EStateMask) | ECommitted;
sl@0
   177
		}
sl@0
   178
sl@0
   179
	/**
sl@0
   180
	Update the physical address in the array entry \a aEntry.
sl@0
   181
	@param aEntry		A reference to the entry to update.
sl@0
   182
	@param aPhysAddr	The new physical address.
sl@0
   183
	*/
sl@0
   184
	static FORCE_INLINE void PageMoveNewAddr(TPhysAddr& aEntry, TPhysAddr aPhysAddr)
sl@0
   185
		{
sl@0
   186
		__NK_ASSERT_DEBUG(!(aPhysAddr & EStateMask));
sl@0
   187
		__NK_ASSERT_DEBUG(State(aEntry) == EMoving);
sl@0
   188
		aEntry = (aEntry & EStateMask) | aPhysAddr;
sl@0
   189
		}
sl@0
   190
sl@0
   191
	static void Init2A();
sl@0
   192
	static void Init2B(DMutex* aLock);
sl@0
   193
sl@0
   194
	RPageArray();
sl@0
   195
	~RPageArray();
sl@0
   196
sl@0
   197
	/**
sl@0
   198
	Second stage constructor for the array.
sl@0
   199
sl@0
   200
	@param aMaxPages			The maximum number of entries to be stored in the array.
sl@0
   201
	@param aPreallocateMemory	If true, then all the memory required to store the array
sl@0
   202
								entries is allocated immediately - rather than on demand
sl@0
   203
								as entries are added.
sl@0
   204
	*/
sl@0
   205
	TInt Construct(TUint aMaxPages, TBool aPreallocateMemory=EFalse);
sl@0
   206
sl@0
   207
	/**
sl@0
   208
	Allocate all memory required to store array entries.
sl@0
   209
	This is only for use during system boot.
sl@0
   210
	*/
sl@0
   211
	TInt PreallocateMemory();
sl@0
   212
sl@0
   213
	/**
sl@0
   214
	Ensures the memory to store a region of array entries is allocated and locked.
sl@0
   215
sl@0
   216
	@param aIndex	Start index of region.
sl@0
   217
	@param aCount	Number of pages in region.
sl@0
   218
sl@0
   219
	@see RPageArray::Free()
sl@0
   220
	*/
sl@0
   221
	TInt Alloc(TUint aIndex, TUint aCount);
sl@0
   222
sl@0
   223
	/**
sl@0
   224
	Revert the action of #Alloc by unlocking the memory used for a region of array entries.
sl@0
   225
	Note, calling #Free for any entry more times than #Alloc was used will have
sl@0
   226
	unpredictable results.
sl@0
   227
sl@0
   228
	@param aIndex	Start index of region.
sl@0
   229
	@param aCount	Number of pages in region.
sl@0
   230
	*/
sl@0
   231
	void Free(TUint aIndex, TUint aCount);
sl@0
   232
sl@0
   233
	/**
sl@0
   234
	Prepare to add (commit) pages to a region in this array.
sl@0
   235
	This ensures the memory to store the entries is allocated and locked. It also,
sl@0
   236
	optionally and by default, check that these entries are empty.
sl@0
   237
sl@0
   238
	@param aIndex			Start index of region.
sl@0
   239
	@param aCount			Number of pages in region.
sl@0
   240
	@param[out] aIter		An iterator which covers the specified region.
sl@0
   241
	@param aAllowExisting	True if the region may contain non-empty entries.
sl@0
   242
							False to assert entries are empty.
sl@0
   243
sl@0
   244
	@see RPageArray::AddEnd()
sl@0
   245
	*/
sl@0
   246
	TInt AddStart(TUint aIndex, TUint aCount, TIter& aIter, TBool aAllowExisting=EFalse);
sl@0
   247
sl@0
   248
	/**
sl@0
   249
	End an 'add' operation started with #AddStart.
sl@0
   250
	This must be called to unlock any page array memory which #AddStart locked.
sl@0
   251
sl@0
   252
	@param aIndex	Start index of region. Must be same value as corresponding call to #AddStart.
sl@0
   253
	@param aCount	Number of pages in region. Must be same value as corresponding call to #AddStart.
sl@0
   254
	*/
sl@0
   255
	void AddEnd(TUint aIndex, TUint aCount);
sl@0
   256
sl@0
   257
	/**
sl@0
   258
	Prepare to search a region in this array.
sl@0
   259
sl@0
   260
	@param aIndex			Start index of region.
sl@0
   261
	@param aCount			Number of pages in region.
sl@0
   262
	@param[out] aIter		An iterator which covers the specified region.
sl@0
   263
sl@0
   264
	@see RPageArray::AddEnd()
sl@0
   265
	*/
sl@0
   266
	void FindStart(TUint aIndex, TUint aCount, TIter& aIter);
sl@0
   267
sl@0
   268
	/**
sl@0
   269
	End a find operation started with #FindStart.
sl@0
   270
sl@0
   271
	@param aIndex	Start index of region. Must be same value as corresponding call to #FindStart.
sl@0
   272
	@param aCount	Number of pages in region. Must be same value as corresponding call to #FindStart.
sl@0
   273
	*/
sl@0
   274
	void FindEnd(TUint aIndex, TUint aCount);
sl@0
   275
sl@0
   276
	/**
sl@0
   277
	Prepare to add (commit) a single page to this array.
sl@0
   278
	This ensures the memory to store the entry is allocated and locked.
sl@0
   279
sl@0
   280
	@param aIndex			Index of entry.
sl@0
   281
	@param[out] aPageList	An iterator represents the single array entry.
sl@0
   282
sl@0
   283
	@return Pointer to the array entry,
sl@0
   284
			or the null pointer if memory allocation failed.
sl@0
   285
sl@0
   286
	@see RPageArray::AddPage()
sl@0
   287
	@see RPageArray::AddPageEnd()
sl@0
   288
	*/
sl@0
   289
	TPhysAddr* AddPageStart(TUint aIndex, TIter& aPageList);
sl@0
   290
sl@0
   291
	/**
sl@0
   292
	Add (commit) a single page to the array.
sl@0
   293
sl@0
   294
	@param aPageEntry	The address of the array entry as returned by AddPageStart.
sl@0
   295
	@param aPage		The physical address of the page being added.
sl@0
   296
	*/
sl@0
   297
	static void AddPage(TPhysAddr* aPageEntry, TPhysAddr aPage);
sl@0
   298
sl@0
   299
	/**
sl@0
   300
	End an 'add' operation started with #AddPageStart.
sl@0
   301
	This must be called to unlock any page array memory which #AddPageStart locked.
sl@0
   302
sl@0
   303
	@param aIndex	Index of entry. Must be same value as corresponding call to #AddPageStart.
sl@0
   304
	@param aDelta	1 (one), if the array entry was changed from ENotPresent state (e.g. AddPage called),
sl@0
   305
					zero otherwise.
sl@0
   306
	*/
sl@0
   307
	void AddPageEnd(TUint aIndex, TInt aDelta);
sl@0
   308
sl@0
   309
	/**
sl@0
   310
	Prepare to remove (decommit) a single page from this array.
sl@0
   311
sl@0
   312
	This function is similar to TIter::RemoveFind and updates the array entry and
sl@0
   313
	memory locking in the same way.
sl@0
   314
sl@0
   315
	@param aIndex			Index of entry.
sl@0
   316
	@param[out] aPageList	An iterator representing the single array entry.
sl@0
   317
							Not set if this method returns the null pointer.
sl@0
   318
sl@0
   319
	@return Pointer to the array entry,
sl@0
   320
			or the null pointer if entry does not need decommitting.
sl@0
   321
sl@0
   322
	@see RPageArray::RemovePage()
sl@0
   323
	@see RPageArray::RemovePageEnd()
sl@0
   324
	*/
sl@0
   325
	TPhysAddr* RemovePageStart(TUint aIndex, TIter& aPageList);
sl@0
   326
sl@0
   327
	/**
sl@0
   328
	Remove a single page from the array.
sl@0
   329
sl@0
   330
	This function is similar to TIter::Remove and updates the array entry in the same way.
sl@0
   331
sl@0
   332
	@param aPageEntry	The address of the array entry as returned by RemovePageStart.
sl@0
   333
sl@0
   334
	@return The physical address of the page which was removed,
sl@0
   335
			or KPhysAddrInvalid if no page was removed.
sl@0
   336
	*/
sl@0
   337
	static TPhysAddr RemovePage(TPhysAddr* aPageEntry);
sl@0
   338
sl@0
   339
	/**
sl@0
   340
	End an 'remove' operation started with #RemovePageStart.
sl@0
   341
	This must be called to unlock any page array memory which #RemovePageStart locked.
sl@0
   342
sl@0
   343
	@param aIndex	Index of entry. Must be same value as corresponding call to #RemovePageStart.
sl@0
   344
	@param aDelta	1 (one), if the array entry was set ENotPresent state (RemovePage succeeded),
sl@0
   345
					zero otherwise.
sl@0
   346
	*/
sl@0
   347
	void RemovePageEnd(TUint aIndex, TInt aDelta);
sl@0
   348
sl@0
   349
	/**
sl@0
   350
	Prepare to restrict access to a single page in this array.
sl@0
   351
sl@0
   352
	If the page entry state indicates that the page is already more restricted
sl@0
   353
	than being requested, then the function returns the null pointer and does nothing.
sl@0
   354
sl@0
   355
	If the page does need its access restricting then its entry in the array is set to
sl@0
   356
	ERestrictingNA and the memory for the entry is locked.
sl@0
   357
sl@0
   358
	@param aIndex			Index of entry.
sl@0
   359
	@param[out] aPageList	An iterator representing the single array entry.
sl@0
   360
							Not set if this method returns the null pointer.
sl@0
   361
sl@0
   362
	@return Pointer to the array entry,
sl@0
   363
			or the null pointer if entry does not need it's access restricting further.
sl@0
   364
sl@0
   365
	@see RPageArray::RestrictPageNAEnd()
sl@0
   366
	*/
sl@0
   367
	TPhysAddr* RestrictPageNAStart(TUint aIndex, TIter& aPageList);
sl@0
   368
sl@0
   369
	/**
sl@0
   370
	End an 'restrict' operation started with #RestrictPageStart.
sl@0
   371
	This must be called to unlock any page array memory which #RestrictPageStart locked.
sl@0
   372
sl@0
   373
	@param aIndex	Index of entry. Must be same value as corresponding call to #RestrictPageStart.
sl@0
   374
	*/
sl@0
   375
	void RestrictPageNAEnd(TUint aIndex);
sl@0
   376
sl@0
   377
	/**
sl@0
   378
	Prepare to steal a single page from this array.
sl@0
   379
sl@0
   380
	The memory for the entry is locked and if the page entry is is in one of the committed
sl@0
   381
	states then it is changed to state EStealing.
sl@0
   382
sl@0
   383
	@param aIndex			Index of entry.
sl@0
   384
	@param[out] aPageList	An iterator representing the single array entry.
sl@0
   385
							Not set if this method returns the null pointer.
sl@0
   386
sl@0
   387
	@return Pointer to the array entry.
sl@0
   388
sl@0
   389
	@see RPageArray::StealPageEnd()
sl@0
   390
	*/
sl@0
   391
	TPhysAddr* StealPageStart(TUint aIndex, TIter& aPageList);
sl@0
   392
sl@0
   393
	/**
sl@0
   394
	End an 'steal' operation started with #StealPageStart.
sl@0
   395
	This must be called to unlock any page array memory which #StealPageStart locked.
sl@0
   396
sl@0
   397
	@param aIndex	Index of entry. Must be same value as corresponding call to #StealPageStart.
sl@0
   398
	@param aDelta	1 (one), if the array entry was set ENotPresent state (the page was stolen),
sl@0
   399
					zero otherwise.
sl@0
   400
	*/
sl@0
   401
	void StealPageEnd(TUint aIndex, TInt aDelta);
sl@0
   402
sl@0
   403
	/**
sl@0
   404
	Prepare to move a page in this array by changing its state to EMoving.
sl@0
   405
sl@0
   406
	Note - the memory entry isn't locked as the RamAllocLock mutex must be held 
sl@0
   407
	through out	the page moving process and therefore the page cannot be removed.
sl@0
   408
sl@0
   409
	@param aIndex			The index of the entry to be moved.
sl@0
   410
	@param[out] aPageList	An iterator representing the single array entry.
sl@0
   411
							Not set if this method returns the null pointer.
sl@0
   412
sl@0
   413
	@return Pointer to the array entry, NULL if the page cannot be moved.
sl@0
   414
	
sl@0
   415
	@see RPageArray::MovePageEnd()
sl@0
   416
	*/
sl@0
   417
	TPhysAddr* MovePageStart(TUint aIndex, TIter& aPageList);
sl@0
   418
sl@0
   419
	/**
sl@0
   420
	Return the array entry for index \a aIndex.
sl@0
   421
	*/
sl@0
   422
	TPhysAddr Page(TUint aIndex);
sl@0
   423
sl@0
   424
sl@0
   425
	/**
sl@0
   426
	Return a pointer to the array entry for index \a aIndex.
sl@0
   427
sl@0
   428
	@return Pointer to the array entry, NULL if the page cannot found.
sl@0
   429
	*/
sl@0
   430
	TPhysAddr* PageEntry(TUint aIndex);
sl@0
   431
sl@0
   432
	/**
sl@0
   433
	Return the physical address of the page at index \a aIndex, or KPhysAddrInvalid if none present.
sl@0
   434
	*/
sl@0
   435
	TPhysAddr PhysAddr(TUint aIndex);
sl@0
   436
sl@0
   437
	/**
sl@0
   438
	Get the physical address for the pages stored in the specified region in the array.
sl@0
   439
sl@0
   440
	@param aIndex					Start index of region.
sl@0
   441
	@param aCount					Number of pages in region.
sl@0
   442
	@param[out] aPhysicalAddress	If all pages are physically contiguous this is set to the start address,
sl@0
   443
									otherwise this is set to KPhysAddrInvalid.
sl@0
   444
	@param[out] aPhysicalPageList	Pointer to array of \a aCount physical addresses which
sl@0
   445
									will be filled with the physical addressed of each page in the region.
sl@0
   446
sl@0
   447
	@return	0 (zero) if all pages in region are physically contiguous;
sl@0
   448
			1 (one) if pages are not physically contiguous;
sl@0
   449
			KErrNotFound, if any page in the region is not present.		
sl@0
   450
	*/
sl@0
   451
	TInt PhysAddr(TUint aIndex, TUint aCount, TPhysAddr& aPhysicalAddress, TPhysAddr* aPhysicalPageList);
sl@0
   452
sl@0
   453
	enum
sl@0
   454
		{
sl@0
   455
		/**
sl@0
   456
		Maximum number of bits which can be stored in an array entry by SetPagingManagerData.
sl@0
   457
		*/
sl@0
   458
		KPagingManagerDataBits		= 32-(EFlagsShift+EStateShift),
sl@0
   459
		};
sl@0
   460
sl@0
   461
	enum
sl@0
   462
		{
sl@0
   463
		/**
sl@0
   464
		Maximum value which can be stored in an array entry by SetPagingManagerData.
sl@0
   465
		*/
sl@0
   466
		KMaxPagingManagerData		= (1u<<KPagingManagerDataBits)-1u
sl@0
   467
		};
sl@0
   468
sl@0
   469
	/**
sl@0
   470
	Write \a aValue to the paging manager data for index \a aIndex.
sl@0
   471
	The value must not exceed KMaxPagingManagerData.
sl@0
   472
sl@0
   473
	This value is stored in the page array entry, if it's state is ENotPresent;
sl@0
   474
	otherwise it is stored in the SPageInfo object for the page in the array entry.
sl@0
   475
	*/
sl@0
   476
	void SetPagingManagerData(TUint aIndex, TUint aValue);
sl@0
   477
sl@0
   478
	/**
sl@0
   479
	Return the paging manager data for index \a aIndex.
sl@0
   480
	@see RPageArray::SetPagingManagerData()
sl@0
   481
	*/
sl@0
   482
	TUint PagingManagerData(TUint aIndex);
sl@0
   483
sl@0
   484
sl@0
   485
private:
sl@0
   486
	/**
sl@0
   487
	Unlock the memory used for a region of array entries.
sl@0
   488
sl@0
   489
	@param aSegments	Copy of RPageArray::iSegments from the array.
sl@0
   490
	@param aIndex		Start index of region.
sl@0
   491
	@param aCount		Number of pages in region.
sl@0
   492
	*/
sl@0
   493
	static void Release(TSegment** aSegments, TUint aIndex, TUint aCount);
sl@0
   494
sl@0
   495
	/**
sl@0
   496
	Unlocking the memory used for a single array entry.
sl@0
   497
	This also updates
sl@0
   498
sl@0
   499
	@param aIndex The index of the array entry.
sl@0
   500
	@param aDelta The change in the 'present' state for the entry. This is
sl@0
   501
				  1 if the entry was added (state changed from ENotPresent),
sl@0
   502
				  -1 if the entry was removed (state changed to ENotPresent),
sl@0
   503
				  0 otherwise.
sl@0
   504
	*/
sl@0
   505
	void ReleasePage(TUint aIndex, TInt aDelta);
sl@0
   506
sl@0
   507
	/**
sl@0
   508
	Return the array segment in at \a aSegmentEntry, allocating a new one to this if
sl@0
   509
	none previously existed. Return the null pointer in no segment could be allocated
sl@0
   510
	(out of memory).
sl@0
   511
sl@0
   512
	The returned segment is locked (TSegment::Lock) \a aLockCount times; this normally
sl@0
   513
	represents the number of entries in the segment which are to be accesses.
sl@0
   514
	*/
sl@0
   515
	TSegment* GetOrAllocateSegment(TSegment** aSegmentEntry, TUint aLockCount);
sl@0
   516
private:
sl@0
   517
	TUint8 iPreallocatedMemory; ///< Set true, if this array was constructed with pre-allocated memory. See #Construct.
sl@0
   518
	TUint iNumSegments;			///< The number of segments in array iSegments.
sl@0
   519
	TSegment** iSegments;		///< Array of TSegment objects allocated for this array. May contain null pointers.
sl@0
   520
sl@0
   521
public:
sl@0
   522
	/**
sl@0
   523
	Class for iterating through and manipulating a section of entries in an RPageArray.
sl@0
   524
	*/
sl@0
   525
	class TIter
sl@0
   526
		{
sl@0
   527
	public:
sl@0
   528
		/**
sl@0
   529
		Find the next region of empty entries.
sl@0
   530
sl@0
   531
		@param[out] aPageList	The found region.
sl@0
   532
								The #Add or #AddContiguous method is normally subsequently used on this.
sl@0
   533
sl@0
   534
		@return The number of pages in the found region. Zero indicating no more empty entries were found.
sl@0
   535
sl@0
   536
		@post This iterator is updated start immediately after the found region returned in \a aPageList.
sl@0
   537
		*/
sl@0
   538
		TUint AddFind(TIter& aPageList);
sl@0
   539
sl@0
   540
		/**
sl@0
   541
		Add pages to the array, setting each entry state as ECommitted.
sl@0
   542
sl@0
   543
		@param aCount		The number of pages to add.
sl@0
   544
		@param aPages		Pointer to list of \a aCount physical page addresses to add.
sl@0
   545
		*/
sl@0
   546
		void Add(TUint aCount, TPhysAddr* aPages);
sl@0
   547
sl@0
   548
		/**
sl@0
   549
		Add contiguous pages to the array, setting each entry state as ECommitted.
sl@0
   550
sl@0
   551
		@param aCount		The number of pages to add.
sl@0
   552
		@param aPhysAddr	The physical address of the first page to add.
sl@0
   553
		*/
sl@0
   554
		void AddContiguous(TUint aCount, TPhysAddr aPhysAddr);
sl@0
   555
sl@0
   556
		/**
sl@0
   557
		Update iterator and array state as if pages had been added with #Add.
sl@0
   558
		This is used after array entries have been directly manipulated rather
sl@0
   559
		than being updated through #Add.
sl@0
   560
sl@0
   561
		@param aCount	The number of pages to move this iterator on by.
sl@0
   562
		@param aChanged	The number of new entries which have been added to the array.
sl@0
   563
		*/
sl@0
   564
		void Added(TUint aCount, TUint aChanged);
sl@0
   565
sl@0
   566
		/**
sl@0
   567
		Find the next region of non-empty entries and lock the memory used to store these.
sl@0
   568
sl@0
   569
		@param[out] aPageList	The found region.
sl@0
   570
								The #Pages method is normally subsequently used on this.
sl@0
   571
sl@0
   572
		@return The number of pages in the found region. Zero indicating no more empty entries were found.
sl@0
   573
sl@0
   574
		@post This iterator is updated to start at the first found entry.
sl@0
   575
sl@0
   576
		@see RPageArray::FindRelease()
sl@0
   577
		*/
sl@0
   578
		TUint Find(TIter& aPageList);
sl@0
   579
sl@0
   580
		/**
sl@0
   581
		Unlock the page array memory locked by #Find or #RemoveFind and move this iterator
sl@0
   582
		past this region in preparation for a subsequent find operation.
sl@0
   583
sl@0
   584
		@param aCount	The number of pages returned by the corresponding find function.
sl@0
   585
sl@0
   586
		@post This iterator is updated to start immediately after the region
sl@0
   587
			  returned by the corresponding find function.
sl@0
   588
		*/
sl@0
   589
		void FindRelease(TUint aCount);
sl@0
   590
sl@0
   591
		/**
sl@0
   592
		Find the next region of entries to be removed (decommitted).
sl@0
   593
		The entries found are those which are neither empty nor in state EDecommitted.
sl@0
   594
		They are updated to state EDecommitting and the memory used to store these entries
sl@0
   595
		is locked. To unlock the memory and continue searching FindRelease
sl@0
   596
sl@0
   597
		@param[out] aPageList	The found region.
sl@0
   598
								The #Remove method is normally subsequently used on this.
sl@0
   599
sl@0
   600
		@return The number of pages in the found region. Zero indicating no more empty entries were found.
sl@0
   601
sl@0
   602
		@post This iterator is updated to start at the first found entry.
sl@0
   603
sl@0
   604
		@see RPageArray::FindRelease()
sl@0
   605
		@see RPageArray::Remove()
sl@0
   606
		*/
sl@0
   607
		TUint RemoveFind(TIter& aPageList);
sl@0
   608
sl@0
   609
		/**
sl@0
   610
		Remove pages from the array.
sl@0
   611
sl@0
   612
		For each entry found to be in the EDecommitting state (as set by #RemoveFind)
sl@0
   613
		the page address in the entry is appended to the supplied array (\a aPages) and
sl@0
   614
		the entry set to EEmptyEntry. However, if the array entry has the EUnmapVetoed flag set
sl@0
   615
		then instead the entry state is set to EDecommitted and the page address is not appended
sl@0
   616
		to \a aPages.
sl@0
   617
sl@0
   618
		@param aMaxCount	The maximum number of pages to remove.
sl@0
   619
		@param[out] aPages	Pointer to array of \a aMaxCount physical addresses which
sl@0
   620
							will be set to the physical addresses of the pages removed.
sl@0
   621
sl@0
   622
		@return The number of pages removed from the array and stored at \a aPages.
sl@0
   623
sl@0
   624
		@post This iterator is updated start immediately after the last removed entry.
sl@0
   625
		*/
sl@0
   626
		TUint Remove(TUint aMaxCount, TPhysAddr* aPages);
sl@0
   627
sl@0
   628
		/**
sl@0
   629
		Return a pointer to the array entries represented by this iterator.
sl@0
   630
sl@0
   631
		As array entries may not be stored contiguously in memory this method returns the
sl@0
   632
		number of valid entries.
sl@0
   633
sl@0
   634
		This method should only be used for array entries which have had their
sl@0
   635
		memory locked or for which there are other guarantees that the memory is present.
sl@0
   636
sl@0
   637
		@param[out] aStart	Set to the address of the first array entry.
sl@0
   638
		@param aMaxCount	The maximum count this function should return.
sl@0
   639
sl@0
   640
		@return The number of array entries starting at \a aStart which are valid.
sl@0
   641
		*/
sl@0
   642
		TUint Pages(TPhysAddr*& aStart, TUint aMaxCount=~0u);
sl@0
   643
sl@0
   644
		/**
sl@0
   645
		Move this iterator on by \a aCount pages.
sl@0
   646
		*/
sl@0
   647
		void Skip(TUint aCount);
sl@0
   648
sl@0
   649
		/**
sl@0
   650
		Prevent pages in the region covered by this iterator from having their
sl@0
   651
		access restricted. This is achieved by returning any entries currently
sl@0
   652
		in the specified 'being restricted' state to be fully committed again (state ECommitted).
sl@0
   653
sl@0
   654
		@param aPageMoving ETrue to veto pages being restricted for page moving (EMoving). Set to EFalse otherwise.
sl@0
   655
		*/
sl@0
   656
		void VetoRestrict(TBool aPageMoving);
sl@0
   657
sl@0
   658
		/**
sl@0
   659
		Prevent pages in the region covered by this iterator from being removed from the array.
sl@0
   660
		This is achieved by setting the EUnmapVetoed flag for all entries with a current state
sl@0
   661
		indicating they are being decommitted, c.f. TargetStateIsDecommitted.
sl@0
   662
		*/
sl@0
   663
		void VetoUnmap();
sl@0
   664
sl@0
   665
		/**
sl@0
   666
		Default constructor which does not initialise members.
sl@0
   667
		*/
sl@0
   668
		TIter();
sl@0
   669
sl@0
   670
		/**
sl@0
   671
		Return a new iterator which represents the array region [aIndex..aEndIndex).
sl@0
   672
		The new region is asserted to be within that specified by this iterator.
sl@0
   673
		*/
sl@0
   674
		TIter Slice(TUint aIndex, TUint aEndIndex);
sl@0
   675
sl@0
   676
		/**
sl@0
   677
		Return a new iterator which represents the first \a aCount pages of this one.
sl@0
   678
		*/
sl@0
   679
		TIter Left(TUint aCount);
sl@0
   680
sl@0
   681
		/**
sl@0
   682
		Return the start index of the region being represented by this iterator.
sl@0
   683
		*/
sl@0
   684
		FORCE_INLINE TUint Index() const
sl@0
   685
			{ return iIndex; }
sl@0
   686
sl@0
   687
		/**
sl@0
   688
		Return the index immediately after the being represented by this iterator.
sl@0
   689
		*/
sl@0
   690
		FORCE_INLINE TUint IndexEnd() const
sl@0
   691
			{ return iEndIndex; }
sl@0
   692
sl@0
   693
		/**
sl@0
   694
		Return the number of entries in the region represented by this iterator.
sl@0
   695
		*/
sl@0
   696
		FORCE_INLINE TUint Count() const
sl@0
   697
			{ return iEndIndex-iIndex; }
sl@0
   698
sl@0
   699
	private:
sl@0
   700
		TIter(TSegment** aSegments, TUint aIndex, TUint aEndIndex);
sl@0
   701
		void Set(TSegment** aSegments, TUint aIndex, TUint aEndIndex);
sl@0
   702
	private:
sl@0
   703
		TSegment** iSegments;	///< Copy of RPageArray::iSegments of the array being represented by this iterator.
sl@0
   704
		TUint iIndex;			///< Start index of the array region being represented by this iterator.
sl@0
   705
		TUint iEndIndex;		///< The index immediately after the array region being represented by this iterator.
sl@0
   706
sl@0
   707
		friend class RPageArray;
sl@0
   708
		};
sl@0
   709
sl@0
   710
	/**
sl@0
   711
	Class representing the memory storage for a 'segment' of entries in an RPageArray.
sl@0
   712
	Each segment contains storage for #KPageArraySegmentSize entries and the number
sl@0
   713
	of these which are not #EEmptyEntry are counted by the 'alloc count'.
sl@0
   714
	Each segment also has a 'lock count' which acts as a reference count preventing
sl@0
   715
	the segment from being deleted whilst it is being manipulated.
sl@0
   716
	Both of these counts are combined in #iCounts.
sl@0
   717
	*/
sl@0
   718
	class TSegment
sl@0
   719
		{
sl@0
   720
	private:
sl@0
   721
		/**
sl@0
   722
		Return a newly allocated segment or the null pointer if out-ot-memory.
sl@0
   723
		*/
sl@0
   724
		static TSegment* New();
sl@0
   725
sl@0
   726
		/**
sl@0
   727
		Delete \a aSegment and return the null pointer.
sl@0
   728
		*/
sl@0
   729
		static TSegment* Delete(TSegment* aSegment);
sl@0
   730
sl@0
   731
		/**
sl@0
   732
		Lock this segment \a aCount times. This prevents the segment being deleted.
sl@0
   733
		*/
sl@0
   734
		void Lock(TUint aCount=1);
sl@0
   735
sl@0
   736
		/**
sl@0
   737
		Unlock \a aSegment \a aCount times.
sl@0
   738
		If the lock count reaches zero and the segment has no allocated entries
sl@0
   739
		then it is deleted and \a aSegment set to the null pointer.
sl@0
   740
		*/
sl@0
   741
		static TBool Unlock(TSegment*& aSegment, TUint aCount=1);
sl@0
   742
sl@0
   743
		/**
sl@0
   744
		Adjust the allocation count for this segment by \a aDelta.
sl@0
   745
		The allocation count keeps count of the number of entries which are not #EEmptyEntry.
sl@0
   746
		*/
sl@0
   747
		void AdjustAllocCount(TInt aDelta);
sl@0
   748
sl@0
   749
		/**
sl@0
   750
		Debug function which outputs the contents of this segment to the kernel debug port.
sl@0
   751
		*/
sl@0
   752
		void Dump();
sl@0
   753
	private:
sl@0
   754
		/**
sl@0
   755
		Storage for each array entry.
sl@0
   756
		*/
sl@0
   757
		TPhysAddr iPages[KPageArraySegmentSize];
sl@0
   758
sl@0
   759
		/**
sl@0
   760
		Two count values are stored in this member.
sl@0
   761
		Bits 0..KPageArraySegmentAllocCountShift-1 is the 'lock count' modified by the
sl@0
   762
		Lock and Unlock methods.
sl@0
   763
		Bits KPageArraySegmentAllocCountShift..31 is the 'alloc count' modified by the
sl@0
   764
		AdjustAllocCount method.
sl@0
   765
		When both counts are zero, this segment is empty and not being used,
sl@0
   766
		and can therefore be deleted.
sl@0
   767
		Note, the alloc count is only valid when the lock count is zero, i.e.
sl@0
   768
		after all users have finished updating this segment.
sl@0
   769
		*/
sl@0
   770
		TUint iCounts;
sl@0
   771
sl@0
   772
		friend class RPageArray;
sl@0
   773
		friend class TIter;
sl@0
   774
		};
sl@0
   775
sl@0
   776
	friend class RPageArray::TSegment;
sl@0
   777
	friend class RPageArray::TIter;
sl@0
   778
	};
sl@0
   779
sl@0
   780
sl@0
   781
sl@0
   782
//
sl@0
   783
// RPageArray::TIter
sl@0
   784
//
sl@0
   785
sl@0
   786
FORCE_INLINE RPageArray::TIter::TIter()
sl@0
   787
	{
sl@0
   788
#ifdef _DEBUG
sl@0
   789
	iSegments = 0;
sl@0
   790
	iIndex = 0;
sl@0
   791
	iEndIndex = ~0u;
sl@0
   792
#endif
sl@0
   793
	}
sl@0
   794
sl@0
   795
FORCE_INLINE RPageArray::TIter::TIter(RPageArray::TSegment** aSegments, TUint aIndex, TUint aEndIndex)
sl@0
   796
	: iSegments(aSegments), iIndex(aIndex), iEndIndex(aEndIndex)
sl@0
   797
	{
sl@0
   798
	__NK_ASSERT_DEBUG(iEndIndex>=aIndex);
sl@0
   799
	}
sl@0
   800
sl@0
   801
FORCE_INLINE RPageArray::TIter RPageArray::TIter::Slice(TUint aIndex, TUint aEndIndex)
sl@0
   802
	{
sl@0
   803
	__NK_ASSERT_DEBUG(aEndIndex>=aIndex);
sl@0
   804
	__NK_ASSERT_DEBUG(aIndex>=iIndex);
sl@0
   805
	__NK_ASSERT_DEBUG(aEndIndex<=iEndIndex);
sl@0
   806
	return TIter(iSegments,aIndex,aEndIndex);
sl@0
   807
	}
sl@0
   808
sl@0
   809
FORCE_INLINE RPageArray::TIter RPageArray::TIter::Left(TUint aCount)
sl@0
   810
	{
sl@0
   811
	__NK_ASSERT_DEBUG(aCount<=Count());
sl@0
   812
	return TIter(iSegments,iIndex,iIndex+aCount);
sl@0
   813
	}
sl@0
   814
sl@0
   815
FORCE_INLINE void RPageArray::TIter::Skip(TUint aCount)
sl@0
   816
	{
sl@0
   817
	__NK_ASSERT_DEBUG(iIndex+aCount>=iIndex);
sl@0
   818
	__NK_ASSERT_DEBUG(iIndex+aCount<=iEndIndex);
sl@0
   819
	iIndex += aCount;
sl@0
   820
	}
sl@0
   821
sl@0
   822
sl@0
   823
//
sl@0
   824
// RPageArray
sl@0
   825
//
sl@0
   826
sl@0
   827
FORCE_INLINE void RPageArray::FindEnd(TUint /*aIndex*/, TUint /*aCount*/)
sl@0
   828
	{
sl@0
   829
	// nothing to do
sl@0
   830
	}
sl@0
   831
sl@0
   832
FORCE_INLINE void RPageArray::AddPageEnd(TUint aIndex, TInt aDelta)
sl@0
   833
	{
sl@0
   834
	MmuLock::Lock();
sl@0
   835
	ReleasePage(aIndex,aDelta);
sl@0
   836
	MmuLock::Unlock();
sl@0
   837
	}
sl@0
   838
sl@0
   839
FORCE_INLINE void RPageArray::AddPage(TPhysAddr* aPageEntry, TPhysAddr aPage)
sl@0
   840
	{
sl@0
   841
	__NK_ASSERT_DEBUG(MmuLock::IsHeld());
sl@0
   842
	__NK_ASSERT_DEBUG((aPage&KPageMask)==0);
sl@0
   843
	__NK_ASSERT_DEBUG(!RPageArray::IsPresent(*aPageEntry));
sl@0
   844
	*aPageEntry = aPage|RPageArray::ECommitted;
sl@0
   845
	}
sl@0
   846
sl@0
   847
FORCE_INLINE void RPageArray::RestrictPageNAEnd(TUint aIndex)
sl@0
   848
	{
sl@0
   849
	ReleasePage(aIndex,0);
sl@0
   850
	}
sl@0
   851
sl@0
   852
FORCE_INLINE void RPageArray::StealPageEnd(TUint aIndex, TInt aDelta)
sl@0
   853
	{
sl@0
   854
	ReleasePage(aIndex,-aDelta);
sl@0
   855
	}
sl@0
   856
sl@0
   857
FORCE_INLINE void RPageArray::RemovePageEnd(TUint aIndex, TInt aDelta)
sl@0
   858
	{
sl@0
   859
	MmuLock::Lock();
sl@0
   860
	ReleasePage(aIndex,-aDelta);
sl@0
   861
	MmuLock::Unlock();
sl@0
   862
	}
sl@0
   863
sl@0
   864
#endif