kernel/eka/memmodel/epoc/flexible/mmu/mmu.cpp
changeset 132 e4a7b1cbe40c
parent 90 947f0dc9f7a8
child 176 af6ec97d9189
--- a/kernel/eka/memmodel/epoc/flexible/mmu/mmu.cpp	Wed May 05 05:11:16 2010 +0100
+++ b/kernel/eka/memmodel/epoc/flexible/mmu/mmu.cpp	Mon May 10 11:40:53 2010 +0100
@@ -312,7 +312,8 @@
 	}
 
 
-#if 0
+#ifdef FMM_VERIFY_RAM
+// Attempt to write to each unused RAM page and verify the contents.
 void Mmu::VerifyRam()
 	{
 	Kern::Printf("Mmu::VerifyRam() pass 1");
@@ -474,6 +475,10 @@
 					__ASSERT_ALWAYS(r==KErrNone || r==KErrAlreadyExists, Panic(EBadMappedPageAfterBoot));
 					if(pi->Type()==SPageInfo::EUnused)
 						pi->SetFixed();
+#ifdef BTRACE_KERNEL_MEMORY
+					if(r == KErrNone)
+						++Epoc::KernelMiscPages;
+#endif
 					}
 				}
 			}
@@ -500,21 +505,24 @@
 	r = K::MutexCreate(iPhysMemSyncMutex, KLitPhysMemSync, NULL, EFalse, KMutexOrdSyncPhysMem);
 	if(r!=KErrNone)
 		Panic(EPhysMemSyncMutexCreateFailed);
-//	VerifyRam();
+
+#ifdef FMM_VERIFY_RAM
+	VerifyRam();
+#endif
 	}
 
 
 void Mmu::Init2FinalCommon()
 	{
 	__KTRACE_OPT2(KBOOT,KMMU,Kern::Printf("Mmu::Init2FinalCommon"));
-	// hack, reduce free memory to <2GB...
+	// Reduce free memory to <2GB...
 	while(FreeRamInPages()>=0x80000000/KPageSize)
 		{
 		TPhysAddr dummyPage;
 		TInt r = iRamPageAllocator->AllocRamPages(&dummyPage,1, EPageFixed);
 		__NK_ASSERT_ALWAYS(r==KErrNone);
 		}
-	// hack, reduce total RAM to <2GB...
+	// Reduce total RAM to <2GB...
 	if(TheSuperPage().iTotalRamSize<0)
 		TheSuperPage().iTotalRamSize = 0x80000000-KPageSize;
 
@@ -540,6 +548,27 @@
 	iDefrag->Init3(TheMmu.iRamPageAllocator);
 	}
 
+
+void Mmu::BTracePrime(TUint aCategory)
+	{
+	(void)aCategory;
+
+#ifdef BTRACE_RAM_ALLOCATOR
+	// Must check for -1 as that is the default value of aCategory for
+	// BTrace::Prime() which is intended to prime all categories that are 
+	// currently enabled via a single invocation of BTrace::Prime().
+	if(aCategory==BTrace::ERamAllocator || (TInt)aCategory == -1)
+		{
+		NKern::ThreadEnterCS();
+		RamAllocLock::Lock();
+		iRamPageAllocator->DoBTracePrime();
+		RamAllocLock::Unlock();
+		NKern::ThreadLeaveCS();
+		}
+#endif
+	}
+
+
 //
 // Utils
 //
@@ -593,7 +622,7 @@
 	__KTRACE_OPT(KMMU,Kern::Printf("Mmu::ZoneAllocPhysicalRam(?,%d,%d,?,%d)", aZoneIdCount, aBytes, aPhysAddr, aAlign));
 	__NK_ASSERT_DEBUG(RamAllocLock::IsHeld());
 
-	TInt r = iRamPageAllocator->ZoneAllocContiguousRam(aZoneIdList, aZoneIdCount, aBytes, aPhysAddr, EPageFixed, aAlign);
+	TInt r = iRamPageAllocator->ZoneAllocContiguousRam(aZoneIdList, aZoneIdCount, aBytes, aPhysAddr, aAlign);
 	if(r!=KErrNone)
 		iRamAllocFailed = ETrue;
 	else
@@ -619,18 +648,7 @@
 		PagesAllocated(aPageList, aNumPages, (Mmu::TRamAllocFlags)EMemAttStronglyOrdered);
 
 		// update page infos...
-		TUint flash = 0;
-		TPhysAddr* pageEnd = aPageList + aNumPages;
-		MmuLock::Lock();
-		TPhysAddr* page = aPageList;
-		while (page < pageEnd)
-			{
-			MmuLock::Flash(flash,KMaxPageInfoUpdatesInOneGo/2);
-			TPhysAddr pagePhys = *page++;
-			__NK_ASSERT_DEBUG(pagePhys != KPhysAddrInvalid);
-			SPageInfo::FromPhysAddr(pagePhys)->SetPhysAlloc();
-			}
-		MmuLock::Unlock();
+		SetAllocPhysRam(aPageList, aNumPages);
 		}
 	__KTRACE_OPT(KMMU,Kern::Printf("Mmu::ZoneAllocPhysicalRam returns %d",r));
 	return r;
@@ -853,6 +871,22 @@
 	}
 
 
+/**
+Mark a page as being allocated to a particular page type.
+
+NOTE - This page should not be used until PagesAllocated() has been invoked on it.
+
+@param aPhysAddr		The physical address of the page to mark as allocated.
+@param aZonePageType	The type of the page to mark as allocated.
+*/
+void Mmu::MarkPageAllocated(TPhysAddr aPhysAddr, TZonePageType aZonePageType)
+	{
+	__KTRACE_OPT(KMMU,Kern::Printf("Mmu::MarkPageAllocated(0x%x, %d)", aPhysAddr, aZonePageType));
+	__NK_ASSERT_DEBUG(RamAllocLock::IsHeld());
+	iRamPageAllocator->MarkPageAllocated(aPhysAddr, aZonePageType);
+	}
+
+
 void Mmu::FreeRam(TPhysAddr* aPages, TUint aCount, TZonePageType aZonePageType)
 	{
 	__KTRACE_OPT(KMMU,Kern::Printf("Mmu::FreeRam(?,%d)",aCount));
@@ -872,20 +906,31 @@
 		SPageInfo* pi = SPageInfo::FromPhysAddr(pagePhys);
 		PageFreed(pi);
 
-		// If this is an old page of a page being moved that was previously pinned
-		// then make sure it is freed as discardable otherwise despite DPager::DonatePages()
-		// having marked it as discardable it would be freed as movable.
-		__NK_ASSERT_DEBUG(pi->PagedState() != SPageInfo::EPagedPinnedMoved || aCount == 1);
-		if (pi->PagedState() == SPageInfo::EPagedPinnedMoved)
-			aZonePageType = EPageDiscard;
-
-		if(ThePager.PageFreed(pi)==KErrNone)
-			--aCount; // pager has dealt with this page, so one less for us
-		else
+		switch (ThePager.PageFreed(pi))
 			{
-			// All paged pages should have been dealt with by the pager above.
-			__NK_ASSERT_DEBUG(pi->PagedState() == SPageInfo::EUnpaged);
-			*pagesOut++ = pagePhys; // store page address for freeing later
+			case KErrNone: 
+				--aCount; // pager has dealt with this page, so one less for us
+				break;
+			case KErrCompletion:
+				// This was a pager controlled page but it is no longer required.
+				__NK_ASSERT_DEBUG(aZonePageType == EPageMovable || aZonePageType == EPageDiscard);
+				__NK_ASSERT_DEBUG(pi->PagedState() == SPageInfo::EUnpaged);
+				if (aZonePageType == EPageMovable)
+					{// This page was donated to the pager so have to free it here
+					// as aZonePageType is incorrect for this page but aPages may 
+					// contain a mixture of movable and discardable pages.
+					MmuLock::Unlock();
+					iRamPageAllocator->FreeRamPages(&pagePhys, 1, EPageDiscard);
+					aCount--; // We've freed this page here so one less to free later
+					flash = 0;	// reset flash count as we released the mmulock.
+					MmuLock::Lock();
+					break;
+					}
+				// fall through..
+			default:
+				// Free this page..
+				__NK_ASSERT_DEBUG(pi->PagedState() == SPageInfo::EUnpaged);
+				*pagesOut++ = pagePhys; // store page address for freeing later
 			}
 		}
 	MmuLock::Unlock();
@@ -904,21 +949,15 @@
 		__KTRACE_OPT(KMMU,Kern::Printf("Mmu::AllocContiguousRam returns simulated OOM %d",KErrNoMemory));
 		return KErrNoMemory;
 		}
-	// Only the page sets EAllocNoPagerReclaim and it shouldn't allocate contiguous ram.
+	// Only the pager sets EAllocNoPagerReclaim and it shouldn't allocate contiguous ram.
 	__NK_ASSERT_DEBUG(!(aFlags&EAllocNoPagerReclaim));
 #endif
-	TInt r = iRamPageAllocator->AllocContiguousRam(aCount, aPhysAddr, EPageFixed, aAlign+KPageShift);
-	if(r==KErrNoMemory && aCount > KMaxFreeableContiguousPages)
-		{
-		// flush paging cache and retry...
-		ThePager.FlushAll();
-		r = iRamPageAllocator->AllocContiguousRam(aCount, aPhysAddr, EPageFixed, aAlign+KPageShift);
-		}
+	TInt r = iRamPageAllocator->AllocContiguousRam(aCount, aPhysAddr, aAlign+KPageShift);
 	if(r!=KErrNone)
 		iRamAllocFailed = ETrue;
 	else
 		PagesAllocated((TPhysAddr*)(aPhysAddr|1), aCount, aFlags);
-	__KTRACE_OPT(KMMU,Kern::Printf("AllocContiguouseRam returns %d and aPhysAddr=0x%08x",r,aPhysAddr));
+	__KTRACE_OPT(KMMU,Kern::Printf("AllocContiguousRam returns %d and aPhysAddr=0x%08x",r,aPhysAddr));
 	return r;
 	}
 
@@ -963,19 +1002,7 @@
 		return r;
 
 	// update page infos...
-	TPhysAddr* pages = aPages;
-	TPhysAddr* pagesEnd = pages+aCount;
-	MmuLock::Lock();
-	TUint flash = 0;
-	while(pages<pagesEnd)
-		{
-		MmuLock::Flash(flash,KMaxPageInfoUpdatesInOneGo/2);
-		TPhysAddr pagePhys = *pages++;
-		__NK_ASSERT_DEBUG(pagePhys!=KPhysAddrInvalid);
-		SPageInfo* pi = SPageInfo::FromPhysAddr(pagePhys);
-		pi->SetPhysAlloc();
-		}
-	MmuLock::Unlock();
+	SetAllocPhysRam(aPages, aCount);
 
 	return KErrNone;
 	}
@@ -1004,6 +1031,19 @@
 	MmuLock::Unlock();
 
 	iRamPageAllocator->FreeRamPages(aPages,aCount, EPageFixed);
+
+#ifdef BTRACE_KERNEL_MEMORY
+	if (BTrace::CheckFilter(BTrace::EKernelMemory))
+		{// Only loop round each page if EKernelMemory tracing is enabled
+		pages = aPages;
+		pagesEnd = aPages + aCount;
+		while (pages < pagesEnd)
+			{
+			BTrace8(BTrace::EKernelMemory, BTrace::EKernelMemoryDrvPhysFree, KPageSize, *pages++);
+			Epoc::DriverAllocdPhysRam -= KPageSize;
+			}
+		}
+#endif
 	}
 
 
@@ -1015,17 +1055,7 @@
 		return r;
 
 	// update page infos...
-	SPageInfo* pi = SPageInfo::FromPhysAddr(aPhysAddr);
-	SPageInfo* piEnd = pi+aCount;
-	TUint flash = 0;
-	MmuLock::Lock();
-	while(pi<piEnd)
-		{
-		MmuLock::Flash(flash,KMaxPageInfoUpdatesInOneGo);
-		pi->SetPhysAlloc();
-		++pi;
-		}
-	MmuLock::Unlock();
+	SetAllocPhysRam(aPhysAddr, aCount);
 
 	return KErrNone;
 	}
@@ -1050,7 +1080,25 @@
 		}
 	MmuLock::Unlock();
 
-	iRamPageAllocator->FreePhysicalRam(aPhysAddr, aCount << KPageShift);
+	TUint bytes = aCount << KPageShift;
+	iRamPageAllocator->FreePhysicalRam(aPhysAddr, bytes);
+
+#ifdef BTRACE_KERNEL_MEMORY
+	BTrace8(BTrace::EKernelMemory, BTrace::EKernelMemoryDrvPhysFree, bytes, aPhysAddr);
+	Epoc::DriverAllocdPhysRam -= bytes;
+#endif
+	}
+
+
+TInt Mmu::FreeRamZone(TUint aZoneId)
+	{
+	TPhysAddr zoneBase;
+	TUint zonePages;
+	TInt r = iRamPageAllocator->GetZoneAddress(aZoneId, zoneBase, zonePages);
+	if (r != KErrNone)
+		return r;
+	FreePhysicalRam(zoneBase, zonePages);
+	return KErrNone;
 	}
 
 
@@ -1058,25 +1106,11 @@
 	{
 	__KTRACE_OPT(KMMU,Kern::Printf("Mmu::ClaimPhysicalRam(0x%08x,0x%x,0x%08x)",aPhysAddr,aCount,aFlags));
 	aPhysAddr &= ~KPageMask;
-	TInt r = iRamPageAllocator->ClaimPhysicalRam(aPhysAddr,(aCount << KPageShift));
-	if(r!=KErrNone)
+	TInt r = iRamPageAllocator->ClaimPhysicalRam(aPhysAddr, aCount << KPageShift);
+	if(r != KErrNone)
 		return r;
 
-	PagesAllocated((TPhysAddr*)(aPhysAddr|1), aCount, aFlags);
-
-	// update page infos...
-	SPageInfo* pi = SPageInfo::FromPhysAddr(aPhysAddr);
-	SPageInfo* piEnd = pi+aCount;
-	TUint flash = 0;
-	MmuLock::Lock();
-	while(pi<piEnd)
-		{
-		MmuLock::Flash(flash,KMaxPageInfoUpdatesInOneGo);
-		pi->SetPhysAlloc();
-		++pi;
-		}
-	MmuLock::Unlock();
-
+	AllocatedPhysicalRam(aPhysAddr, aCount, aFlags);
 	return KErrNone;
 	}
 
@@ -1088,17 +1122,59 @@
 	PagesAllocated((TPhysAddr*)(aPhysAddr|1), aCount, aFlags);
 
 	// update page infos...
+	SetAllocPhysRam(aPhysAddr, aCount);
+	}
+
+
+void Mmu::SetAllocPhysRam(TPhysAddr aPhysAddr, TUint aCount)
+	{
 	SPageInfo* pi = SPageInfo::FromPhysAddr(aPhysAddr);
 	SPageInfo* piEnd = pi+aCount;
 	TUint flash = 0;
 	MmuLock::Lock();
 	while(pi<piEnd)
 		{
-		MmuLock::Flash(flash,KMaxPageInfoUpdatesInOneGo);
+		MmuLock::Flash(flash, KMaxPageInfoUpdatesInOneGo);
 		pi->SetPhysAlloc();
 		++pi;
 		}
 	MmuLock::Unlock();
+
+#ifdef BTRACE_KERNEL_MEMORY
+	TUint bytes = aCount << KPageShift;
+	BTrace8(BTrace::EKernelMemory, BTrace::EKernelMemoryDrvPhysAlloc, bytes, aPhysAddr);
+	Epoc::DriverAllocdPhysRam += bytes;
+#endif
+	}
+
+
+void Mmu::SetAllocPhysRam(TPhysAddr* aPageList, TUint aNumPages)
+	{
+	TPhysAddr* page = aPageList;
+	TPhysAddr* pageEnd = aPageList + aNumPages;
+	TUint flash = 0;
+	MmuLock::Lock();
+	while (page < pageEnd)
+		{
+		MmuLock::Flash(flash, KMaxPageInfoUpdatesInOneGo / 2);
+		TPhysAddr pagePhys = *page++;
+		__NK_ASSERT_DEBUG(pagePhys != KPhysAddrInvalid);
+		SPageInfo::FromPhysAddr(pagePhys)->SetPhysAlloc();
+		}
+	MmuLock::Unlock();
+
+#ifdef BTRACE_KERNEL_MEMORY
+	if (BTrace::CheckFilter(BTrace::EKernelMemory))
+		{// Only loop round each page if EKernelMemory tracing is enabled
+		TPhysAddr* pAddr = aPageList;
+		TPhysAddr* pAddrEnd = aPageList + aNumPages;
+		while (pAddr < pAddrEnd)
+			{
+			BTrace8(BTrace::EKernelMemory, BTrace::EKernelMemoryDrvPhysAlloc, KPageSize, *pAddr++);
+			Epoc::DriverAllocdPhysRam += KPageSize;
+			}
+		}
+#endif
 	}
 
 
@@ -1187,20 +1263,10 @@
 	__NK_ASSERT_DEBUG(iSize>=1);
 	__NK_ASSERT_DEBUG(iCount==0);
 
-	TUint colour = aColour&KPageColourMask;
-	TLinAddr addr = iLinAddr+(colour<<KPageShift);
-	TPte* pPte = iPtePtr+colour;
-	iColour = colour;
-
-	__ASSERT_DEBUG(*pPte==KPteUnallocatedEntry,MM::Panic(MM::ETempMappingAlreadyInUse));
-	*pPte = (aPage&~KPageMask) | iBlankPte;
-	CacheMaintenance::SinglePteUpdated((TLinAddr)pPte);
-	InvalidateTLBForPage(addr|KKernelOsAsid);
-
-	iCount = 1;
-	return addr;
+	return Map(aPage, aColour, iBlankPte);
 	}
 
+
 /**
 Map a single physical page into this temporary mapping using the given page table entry (PTE) value.
 
@@ -1215,16 +1281,17 @@
 	{
 	__NK_ASSERT_DEBUG(iSize>=1);
 	__NK_ASSERT_DEBUG(iCount==0);
-
-	TUint colour = aColour&KPageColourMask;
-	TLinAddr addr = iLinAddr+(colour<<KPageShift);
-	TPte* pPte = iPtePtr+colour;
+	__NK_ASSERT_DEBUG(!(aBlankPte & ~KPageMask));
+
+	TUint colour = aColour & KPageColourMask;
+	TLinAddr addr = iLinAddr + (colour << KPageShift);
+	TPte* pPte = iPtePtr + colour;
 	iColour = colour;
 
-	__ASSERT_DEBUG(*pPte==KPteUnallocatedEntry,MM::Panic(MM::ETempMappingAlreadyInUse));
-	*pPte = (aPage&~KPageMask) | aBlankPte;
+	__ASSERT_DEBUG(*pPte == KPteUnallocatedEntry, MM::Panic(MM::ETempMappingAlreadyInUse));
+	*pPte = (aPage & ~KPageMask) | aBlankPte;
 	CacheMaintenance::SinglePteUpdated((TLinAddr)pPte);
-	InvalidateTLBForPage(addr|KKernelOsAsid);
+	InvalidateTLBForPage(addr | KKernelOsAsid);
 
 	iCount = 1;
 	return addr;
@@ -1290,19 +1357,16 @@
 	TUint colour = iColour;
 	TLinAddr addr = iLinAddr+(colour<<KPageShift);
 	TPte* pPte = iPtePtr+colour;
-	TUint count = iCount;
-
-	while(count)
+
+	while(iCount)
 		{
 		*pPte = KPteUnallocatedEntry;
 		CacheMaintenance::SinglePteUpdated((TLinAddr)pPte);
 		InvalidateTLBForPage(addr|KKernelOsAsid);
 		addr += KPageSize;
 		++pPte;
-		--count;
+		--iCount;
 		}
-
-	iCount = 0;
 	}
 
 #ifdef __SMP__