kernel/eka/memmodel/epoc/flexible/mmu/mptalloc.h
changeset 0 a41df078684a
child 6 0173bcd7697c
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     1 // Copyright (c) 2007-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 //
       
    15 
       
    16 /**
       
    17  @file
       
    18  @internalComponent
       
    19 */
       
    20 
       
    21 #ifndef MPTALLOC_H
       
    22 #define MPTALLOC_H
       
    23 
       
    24 #include "mcleanup.h"
       
    25 
       
    26 /**
       
    27 Number of #SPageTableInfo structures which will fit into a page of RAM.
       
    28 */
       
    29 const TUint KPageTableInfosPerPage = KPageSize/sizeof(SPageTableInfo);
       
    30 
       
    31 /**
       
    32 Number of pages of page tables which correspond to a page of page infos.
       
    33 */
       
    34 const TUint KPageTableGroupSize = KPageTableInfosPerPage/KPtClusterSize;
       
    35 
       
    36 /**
       
    37 Max number of RAM pages which can be used for page tables.
       
    38 */
       
    39 const TUint KMaxPageTablePages = (KPageTableEnd-KPageTableBase)/KPageSize;
       
    40 
       
    41 
       
    42 /**
       
    43 The maximum number of pages required to pin a single page table.
       
    44 */
       
    45 const TUint KNumPagesToPinOnePageTable = 2; // 1 page table page + 1 page table info page
       
    46 
       
    47 
       
    48 /**
       
    49 Class for allocating MMU page tables.
       
    50 */
       
    51 class PageTableAllocator
       
    52 	{
       
    53 public:
       
    54 	void Init2(DMutex* aLock);
       
    55 	void Init2B();
       
    56 
       
    57 	/**
       
    58 	Allocate a page table.
       
    59 
       
    60 	@param aDemandPaged	True if the page table will be used to map demand paged memory;
       
    61 						false, otherwise.
       
    62 
       
    63 	@return Virtual address of the allocated page table,
       
    64 			or the null-pointer if there was insufficient memory.
       
    65 
       
    66 	@pre #PageTablesLockIsHeld, i.e. current thread has called #Lock()
       
    67 	*/
       
    68 	TPte* Alloc(TBool aDemandPaged);
       
    69 
       
    70 	/**
       
    71 	Free a page table previously aquired with #Alloc.
       
    72 
       
    73 	@param aPageTable	Virtual address of the page table,
       
    74 
       
    75 	@pre #PageTablesLockIsHeld, i.e. current thread has called #Lock()
       
    76 	*/
       
    77 	void Free(TPte* aPageTable);
       
    78 
       
    79 	/**
       
    80 	Acquire the mutex used to protect page table allocation.
       
    81 	*/
       
    82 	void Lock();
       
    83 
       
    84 	/**
       
    85 	Release the mutex used to protect page table allocation.
       
    86 	*/
       
    87 	void Unlock();
       
    88 
       
    89 	/**
       
    90 	Return true if the current thread has acquired the mutex used to protect page table allocation.
       
    91 	I.e. has called #Lock().
       
    92 	*/
       
    93 	TBool LockIsHeld();
       
    94 
       
    95 	/**
       
    96 	Steal a RAM page which is currently being used to store demand paged page tables
       
    97 	or page table infos.
       
    98 
       
    99 	This removes the page tables contained in the RAM from any objects which own
       
   100 	them and then returns the RAM to the demand paging system as a free page. This
       
   101 	will not ever return KErrNone indicating that the page has been successfully
       
   102 	stolen.
       
   103 
       
   104 	This is only intended for use by DPageTableMemoryManager::StealPage.
       
   105 
       
   106 	@param aPageInfo	The page information structure of the page to be stolen.
       
   107 
       
   108 	@return KErrCompletion to indicate that the page was stolen but has been
       
   109 			returned to the demand paging live list as a free page.
       
   110 			Otherwise, KErrInUse if the page was not able to be freed.
       
   111 
       
   112 	@pre #PageTablesLockIsHeld, i.e. current thread has called #Lock()
       
   113 	@pre MmuLock held.
       
   114 	*/
       
   115 	TInt StealPage(SPageInfo* aPageInfo);
       
   116 
       
   117 	/**
       
   118 	Discards a page of page tables or page table infos but only if it is demand paged.
       
   119 	
       
   120 	This will only be invoked on page table info pages or pinned paged tables 
       
   121 	as they aren't on the live list and so M::MovePage() will not know the pager 
       
   122 	can discard them.
       
   123 
       
   124 	@param aMemory		This should always be the page table info memory object.
       
   125 	@param aOldPageInfo	The page info of the page to discard.
       
   126 	@param aBlockZoneId	The ID of any RAM zone not to be allocated into.
       
   127 	@param aBlockRest	ETrue when any allocations should stop if blocked zone hit.
       
   128 
       
   129 	@return KErrNone if the page could be successfully discarded and its RAM page freed.
       
   130 	*/
       
   131 	TInt MovePage(	DMemoryObject* aMemory, SPageInfo* aOldPageInfo, 
       
   132 						TUint aBlockZoneId, TBool aBlockRest);
       
   133 
       
   134 #ifdef _DEBUG
       
   135 	/**
       
   136 	Debug function for use by DPager::RemovePage() to allow it to remove
       
   137 	pages with paged state == EUnpaged.
       
   138 
       
   139 	A page table page may be stolen when it is unpaged as it has been
       
   140 	allocated via DMemoryMapping::AllocatePageTable() but not yet rejuvenated
       
   141 	by Mmu::PageInPages() as the MmuLock is released between these stages.
       
   142 
       
   143 	A page table info page is never added to the live list so it will always
       
   144 	be unpaged but it can be stolen so allow it to be removed.
       
   145 
       
   146 	@param	aPageInfo	The page info of the page.
       
   147 
       
   148 	@return ETrue if the page is a page table info page, EFalse otherwise.
       
   149 	*/
       
   150 	TBool IsPageTableUnpagedRemoveAllowed(SPageInfo* aPageInfo);
       
   151 #endif
       
   152 
       
   153 	/**
       
   154 	Pin the RAM page containing a page table, as well as the RAM page
       
   155 	containing its #SPageTableInfo structure.
       
   156 
       
   157 	@param aPageTable	Virtual address of the page table,
       
   158 	@param aPinArgs		The resources to use for pinning. This must have
       
   159 						at least #KNumPagesToPinOnePageTable replacement
       
   160 						pages available.
       
   161 	*/
       
   162 	static void PinPageTable(TPte* aPageTable, TPinArgs& aPinArgs);
       
   163 
       
   164 	/**
       
   165 	Unpin the RAM page containing a page table, as well as the RAM page
       
   166 	containing its #SPageTableInfo structure.
       
   167 	This reverses the action of #PinPageTable.
       
   168 
       
   169 	@param aPageTable	Virtual address of the page table,
       
   170 	@param aPinArgs		The resources to use for pinning. The replacement
       
   171 						pages count in this will be incremented for each
       
   172 						completely unpinned, e.g. those which can be reused
       
   173 						as new replacement pages or freed.
       
   174 	*/
       
   175 	static void UnpinPageTable(TPte* aPageTable, TPinArgs& aPinArgs);
       
   176 
       
   177 private:
       
   178 	/**
       
   179 	Sub-allocator used for managing page tables of a given 'pagedness' (paged/not-paged).
       
   180 	Each allocator maintains a list free page tables (#iFreeList) from which it can allocate.
       
   181 	As well as a separate list of RAM pages which have no allocated page tables, #iCleanupList.
       
   182 	Page tables in the RAM on #iCleanupList do not appear in #iFreeList.
       
   183 	*/
       
   184 	class TSubAllocator
       
   185 		{
       
   186 	public:
       
   187 		void Init2(PageTableAllocator* iAllocator, TUint aReserveCount, TBool aDemandPaged);
       
   188 
       
   189 		/**
       
   190 		Allocate a page table from this sub-allocator.
       
   191 
       
   192 		@return The #SPageTableInfo structure of the page table,
       
   193 				or the null-pointer if none could be allocated.
       
   194 		*/
       
   195 		SPageTableInfo* Alloc();
       
   196 
       
   197 		/**
       
   198 		Free a page table back to this sub-allocator.
       
   199 
       
   200 		@param aPageTableInfo	The #SPageTableInfo structure of the page table.
       
   201 		*/
       
   202 		void Free(SPageTableInfo* aPageTableInfo);
       
   203 
       
   204 		/**
       
   205 		Add a single page of page tables to this allocator for management.
       
   206 
       
   207 		@param aPageTableInfo	The #SPageTableInfo structure of the first page table
       
   208 								contained in the page.
       
   209 		*/
       
   210 		void AllocPage(SPageTableInfo* aPageTableInfo);
       
   211 
       
   212 		/**
       
   213 		Attempt to remove a single unused page of page tables from this allocator.
       
   214 
       
   215 		@return The #SPageTableInfo structure of the first page table contained
       
   216 				in the removed page. Or the null-pointer if there were no unused
       
   217 				memory to be freed.
       
   218 		*/
       
   219 		SPageTableInfo* FreePage();
       
   220 
       
   221 		/**
       
   222 		Move a page of RAM containing page tables to #iCleanupList.
       
   223 		All page tables in the page must be currently unused.
       
   224 
       
   225 		@param aPageTableInfo	The #SPageTableInfo structure of the first page table
       
   226 								contained in the page.
       
   227 		*/
       
   228 		void MoveToCleanup(SPageTableInfo* aPageTableInfo);
       
   229 
       
   230 		/**
       
   231 		Return true if there are whole RAM pages which can be freed from this
       
   232 		sub-allocator without reducing #iFreeCount below #iReserveCount.
       
   233 		*/
       
   234 		TBool IsCleanupRequired();
       
   235 
       
   236 		/**
       
   237 		Debug check returning true if this objects lists are in a valid state.
       
   238 		*/
       
   239 		TBool CheckFreeList();
       
   240 	public:
       
   241 		SDblQue iFreeList;		///< List of unused page tables, linked by their SPageTableInfo::FreeLink.
       
   242 		SDblQue iCleanupList;	///< List of unused pages, linked by the SPageTableInfo::FreeLink of the first page table in the page.
       
   243 		TUint iFreeCount;		///< Total free page tables in pages on #iFreeList and #iCleanupList.
       
   244 		TUint iReserveCount;	///< Minimum number of page tables to keep in reserve.
       
   245 		TBool iDemandPaged;		///< True if this allocator id used for demand paged page tables.
       
   246 		};
       
   247 
       
   248 	/**
       
   249 	Implementation of #Alloc.
       
   250 	*/
       
   251 	TPte* DoAlloc(TBool aDemandPaged);
       
   252 
       
   253 	/**
       
   254 	Implementation of #Free.
       
   255 	*/
       
   256 	void DoFree(TPte* aPageTable);
       
   257 
       
   258 	/**
       
   259 	Allocate resources for a pages worth of page tables owned by \a aSubAllocator.
       
   260 
       
   261 	@return True if the resources were successfully allocated.
       
   262 
       
   263 	@pre #PageTablesLockIsHeld, i.e. current thread has called #Lock()
       
   264 	*/
       
   265 	TBool AllocReserve(TSubAllocator& aSubAllocator);
       
   266 
       
   267 	/**
       
   268 	Free the resources taken up by a pages worth of unused page tables
       
   269 	owned by \a aSubAllocator.
       
   270 
       
   271 	@return True, if any resources were freed.
       
   272 			False, if there are no more unused resources.
       
   273 
       
   274 	@pre #PageTablesLockIsHeld, i.e. current thread has called #Lock()
       
   275 	*/
       
   276 	TBool FreeReserve(TSubAllocator& aSubAllocator);
       
   277 
       
   278 	/**
       
   279 	Steal a RAM page which is currently being used to store demand paged page 
       
   280 	table infos.
       
   281 
       
   282 	This removes all the page tables references by the page table infos contained in 
       
   283 	the RAM from any objects which own them and then returns the RAM to the demand 
       
   284 	paging system as a free page. This will not ever return KErrNone indicating that 
       
   285 	the page has been successfully stolen.
       
   286 
       
   287 	This is only intended for use by PageTableAllocator::StealPage.
       
   288 
       
   289 	@param aPageInfo	The page information structure of the page to be stolen.
       
   290 
       
   291 	@return KErrCompletion to indicate that the page was stolen but has been
       
   292 			returned to the demand paging live list as a free page.
       
   293 			Otherwise, KErrInUse if the page was not able to be freed.
       
   294 
       
   295 	@pre #PageTablesLockIsHeld, i.e. current thread has called #Lock()
       
   296 	@pre MmuLock held.
       
   297 	*/
       
   298 	TInt StealPageTableInfo(SPageInfo* aPageInfo);
       
   299 
       
   300 	/**
       
   301 	Free all unused resources taken up for page table management.
       
   302 	*/
       
   303 	void Cleanup();
       
   304 
       
   305 	/**
       
   306 	Trampoline function for use with iCleanup which redirects to #Cleanup().
       
   307 	*/
       
   308 	static void CleanupTrampoline(TAny* aSelf);
       
   309 
       
   310 private:
       
   311 	/**
       
   312 	Sub-allocator for allocating unpaged page tables.
       
   313 	*/
       
   314 	TSubAllocator iUnpagedAllocator;
       
   315 
       
   316 	/**
       
   317 	Sub-allocator for allocating demand paged page tables.
       
   318 	*/
       
   319 	TSubAllocator iPagedAllocator;
       
   320 
       
   321 	/**
       
   322 	Object used for queueing cleanup callbacks to #CleanupTrampoline.
       
   323 	*/
       
   324 	TMemoryCleanup iCleanup;
       
   325 
       
   326 	/**
       
   327 	Recursion count for #Alloc.
       
   328 	*/
       
   329 	TUint iAllocating;
       
   330 
       
   331 	/**
       
   332 	The mutex used to protect page table allocation.
       
   333 	*/
       
   334 	DMutex* iLock;
       
   335 
       
   336 	/**
       
   337 	The memory object used to store the memory containing page tables.
       
   338 	*/
       
   339 	DMemoryObject* iPageTableMemory;
       
   340 
       
   341 	/**
       
   342 	The memory object used to store #SPageTableInfo structures.
       
   343 	*/
       
   344 	DMemoryObject* iPageTableInfoMemory;
       
   345 
       
   346 	/**
       
   347 	Helper class for allocating page index values within #iPageTableMemory.
       
   348 	This wraps up to two bitmap allocators, one each used for paged and unpaged
       
   349 	page tables.
       
   350 
       
   351 	Page indexes are allocated in a way which ensures that there will not be
       
   352 	any SPageTableInfo structures for unpaged page tables in the same RAM page
       
   353 	as the structures for paged page tables.
       
   354 	*/
       
   355 	class TPtPageAllocator
       
   356 		{
       
   357 	public:
       
   358 		void Init2(TUint aNumInitPages);
       
   359 		TInt Alloc(TBool aDemandPaged);
       
   360 		void Free(TUint aPageIndex, TBool aDemandPaged);
       
   361 		TBool IsDemandPaged(SPageInfo* aPageInfo)
       
   362 			{// Is the highest page table index this page table info page can reference 
       
   363 			// allocated within the demand paged region of the page table address space.
       
   364 			TUint groupIndex = aPageInfo->Index();
       
   365 			return ((groupIndex+1) * KPageTableGroupSize)-1 >= iUpperWaterMark;
       
   366 			}
       
   367 	private:
       
   368 		TBitMapAllocator* iLowerAllocator; ///< Allocator for unpaged page tables
       
   369 		TUint iLowerWaterMark; ///< Highest page index allocated by iLowerAllocator
       
   370 		TBitMapAllocator* iUpperAllocator; ///< Allocator for demand paged page tables
       
   371 		TUint iUpperWaterMark; ///< Lowest page index allocated by iUpperAllocator
       
   372 		};
       
   373 
       
   374 	/**
       
   375 	Allocator for page indexes within #iPageTableMemory.
       
   376 	*/
       
   377 	TPtPageAllocator iPtPageAllocator;
       
   378 
       
   379 	/**
       
   380 	Array which contains usage for pages of #SPageTableInfo structures.
       
   381 	When the count is zero, there are no structure in use in the corresponding
       
   382 	page of memory in #iPageTableInfoMemory. Indicating that the memory may be
       
   383 	freed.
       
   384 	*/
       
   385 	TUint16 iPageTableGroupCounts[KMaxPageTablePages/KPageTableGroupSize];
       
   386 
       
   387 	friend class TSubAllocator;
       
   388 	};
       
   389 
       
   390 
       
   391 /**
       
   392 The single instance of the #PageTableAllocator.
       
   393 */
       
   394 extern PageTableAllocator PageTables;
       
   395 
       
   396 
       
   397 #endif