kernel/eka/memmodel/emul/win32/mutils.cpp
changeset 0 a41df078684a
child 39 5d2844f35677
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/memmodel/emul/win32/mutils.cpp	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,414 @@
+// Copyright (c) 1994-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// e32\memmodel\emul\win32\mutils.cpp
+// 
+//
+
+#include "memmodel.h"
+#include <kernel/cache.h>
+#include <emulator.h>
+
+void MM::Panic(MM::TMemModelPanic aPanic)
+	{
+	Kern::Fault("MemModel", aPanic);
+	}
+
+TInt M::PageSizeInBytes()
+	{
+	return MM::RamPageSize;
+	}
+
+TBool M::IsRomAddress(const TAny* )
+	{
+	return EFalse;
+	}
+
+TUint32 MM::RoundToPageSize(TUint32 aSize)
+	{
+	TUint32 m=MM::RamPageSize-1;
+	return (aSize+m)&~m;
+	}
+
+EXPORT_C TUint32 Kern::RoundToPageSize(TUint32 aSize)
+	{
+	return MM::RoundToPageSize(aSize);
+	}
+
+EXPORT_C TUint32 Kern::RoundToChunkSize(TUint32 aSize)
+	{
+	return MM::RoundToChunkSize(aSize);
+	}
+
+void MM::Init1()
+	{
+	TheScheduler.SetProcessHandler((TLinAddr)DoProcessSwitch);
+	}
+void MM::Wait()
+	{
+	Kern::MutexWait(*RamAllocatorMutex);
+	if (RamAllocatorMutex->iHoldCount==1)
+		{
+		InitialFreeMemory=FreeMemory;
+		AllocFailed=EFalse;
+		}
+	}
+
+TInt MM::Commit(TLinAddr aBase, TInt aSize, TInt aClearByte, TBool aExecute)
+//
+// Get win32 to commit the pages.
+// We know they are not already committed - this is guaranteed by the caller so we can update the memory info easily
+//
+	{
+	__ASSERT_MUTEX(RamAllocatorMutex);
+
+	if (aSize==0)
+		return KErrNone;
+
+	if (MM::FreeMemory+MM::CacheMemory >= aSize)
+		{
+		__LOCK_HOST;
+		DWORD protect = aExecute ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
+		if (VirtualAlloc(LPVOID(aBase), aSize, MEM_COMMIT, protect))
+			{
+			TInt reclaimed = aSize - MM::FreeMemory;
+			if(reclaimed<=0)
+				MM::FreeMemory -= aSize;
+			else
+				{
+				// some cache memory was needed for this commit...
+				MM::FreeMemory = 0;
+				MM::CacheMemory -= reclaimed;
+				MM::ReclaimedCacheMemory += reclaimed;
+				}
+			MM::CheckMemoryCounters();
+
+			// Clear memory to value determined by chunk member
+			memset(reinterpret_cast<void*>(aBase), aClearByte, aSize);
+
+			return KErrNone;
+			}
+		}
+	MM::AllocFailed = ETrue;
+	return KErrNoMemory;
+	}
+
+TInt MM::Decommit(TLinAddr aBase, TInt aSize)
+//
+// Get win32 to decommit the pages.
+// The pages may or may not be committed: we need to find out which ones are so that the memory info is updated correctly
+//
+	{
+	__ASSERT_MUTEX(RamAllocatorMutex);
+
+	TInt freed = 0;
+	TInt remain = aSize;
+	TLinAddr base = aBase;
+	__LOCK_HOST;
+	while (remain > 0)
+		{
+		MEMORY_BASIC_INFORMATION info;
+		VirtualQuery(LPVOID(base), &info, sizeof(info));
+		TInt size = Min(remain, info.RegionSize);
+		if (info.State == MEM_COMMIT)
+			freed += size;
+
+#ifdef BTRACE_CHUNKS
+		BTraceContext12(BTrace::EChunks,BTrace::EChunkMemoryDeallocated,NULL,base,size);
+#endif
+
+		base += info.RegionSize;
+		remain -= info.RegionSize;
+		}
+	VirtualFree(LPVOID(aBase), aSize, MEM_DECOMMIT);
+	MM::FreeMemory += freed;
+	__KTRACE_OPT(KMEMTRACE, {Kern::Printf("MT:A %d %x %x %O",NTickCount(),NULL,aSize,NULL);});
+
+	return freed;
+	}
+
+void MM::CheckMemoryCounters()
+	{
+	__NK_ASSERT_ALWAYS(MM::CacheMemory>=0);
+	__NK_ASSERT_ALWAYS(MM::ReclaimedCacheMemory>=0);
+	__NK_ASSERT_ALWAYS(MM::FreeMemory+MM::CacheMemory>=0);
+	}
+
+void MM::Signal()
+	{
+	if (RamAllocatorMutex->iHoldCount>1)
+		{
+		Kern::MutexSignal(*RamAllocatorMutex);
+		return;
+		}
+	TInt initial=InitialFreeMemory;
+	TBool failed=AllocFailed;
+	TInt final=FreeMemory;
+	Kern::MutexSignal(*RamAllocatorMutex);
+	K::CheckFreeMemoryLevel(initial,final,failed);
+	}
+
+void MM::DoProcessSwitch(TAny* aAddressSpace)
+// Kernel locked on entry and exit
+	{
+	__NK_ASSERT_LOCKED;
+	
+	if (!aAddressSpace)
+		return;
+	
+	DWin32Process* proc = (DWin32Process*)aAddressSpace;
+
+	if (proc == K::TheKernelProcess) return;
+
+	int count = proc->iDllData.Count();
+	for (int ii=0; ii<count; ii++)
+		{
+		SProcessDllDataBlock& procData = proc->iDllData[ii];
+		DWin32CodeSeg* codeSeg = procData.iCodeSeg;
+		if (!codeSeg)
+			continue;
+		DWin32Process*& liveProc = codeSeg->iLiveProcess;
+		if (liveProc == proc)
+			continue;			// no change in live mapping
+		if (liveProc)
+			{
+			// copy out old process data
+			TInt liveIx = liveProc->iDllData.FindInUnsignedKeyOrder(procData);
+			__ASSERT_ALWAYS(liveIx >= 0,MM::Panic(MM::EWsdDllNotInProcess));
+			SProcessDllDataBlock& oldProcData = liveProc->iDllData[liveIx];
+			memcpy(oldProcData.iDataCopy, (const TAny*)codeSeg->iDataDest, codeSeg->iRealDataSize);
+			memcpy(oldProcData.iBssCopy, (const TAny*)codeSeg->iBssDest, codeSeg->iRealBssSize);
+			}
+		// copy new data in
+		memcpy((TAny*)codeSeg->iDataDest, procData.iDataCopy, codeSeg->iRealDataSize);
+		memcpy((TAny*)codeSeg->iBssDest, procData.iBssCopy, codeSeg->iRealBssSize);
+		liveProc = proc;
+		}
+	}
+
+TAny* MM::CurrentAddress(DThread* aThread, const TAny* aPtr, TInt aSize, TBool /*aWrite*/, TBool& aLocked)
+// Enter and leave with system locked
+// Kernel unlocked on entry
+// Kernel may be locked on exit, iff aPtr is in DLL WSD.
+// this is because the returned address is only valid until the
+// target process DLL WSD changes live status, which can happen 
+// independently when another thread runs.
+// Lock status signaled in aLocked.
+// Why? This allows the optimisation that WSD is only copied on
+// process switch when necessary. The gain from that optimisation is
+// expected to be much higher than the cost of leaving the kernel locked
+// during (rare) IPC to DLL WSD
+	{
+	DWin32Process* proc = (DWin32Process*)aThread->iOwningProcess;
+	// Is the address in DLL static data?
+	NKern::Lock();
+		
+	TInt count = proc->iDllData.Count();
+	TLinAddr p = (TLinAddr)aPtr;
+	TLinAddr base = 0;
+	TInt size = 0;
+	TBool data = EFalse;
+	aLocked = EFalse;
+	for (TInt ii=0; ii<count; ii++)
+		{
+		const SProcessDllDataBlock& procData = proc->iDllData[ii];
+		DWin32CodeSeg* codeSeg = procData.iCodeSeg;
+		if (codeSeg->iDataDest <= p && p < codeSeg->iDataDest + codeSeg->iRealDataSize)
+			{
+			base = codeSeg->iDataDest;
+			size = codeSeg->iRealDataSize;
+			data = ETrue;
+			}
+		else if (codeSeg->iBssDest <= p && p < codeSeg->iBssDest + codeSeg->iRealBssSize)
+			{
+			base = codeSeg->iBssDest;
+			size = codeSeg->iRealBssSize;
+			}
+		if (base)
+			{
+			// This is a DLL static address, check range validity
+			if (p + aSize > base + size)
+				{
+				NKern::Unlock();
+				return NULL;
+				}
+			
+			DWin32Process* liveProc = codeSeg->iLiveProcess;
+
+			if (proc == liveProc)
+				{
+				// If the target process is live, don't remap
+				NKern::Unlock();
+				return (TAny*)aPtr;
+				}
+			else
+				{
+				aLocked = ETrue;
+				TLinAddr procBase = (TLinAddr)(data ? procData.iDataCopy : procData.iBssCopy);
+				TLinAddr remapped = procBase + (p - base);
+				return (TAny*) remapped;
+				}
+			}
+		}
+	NKern::Unlock();
+	// No, the address does not need to be remapped
+	return (TAny*)aPtr;
+	}
+
+void M::BTracePrime(TUint aCategory)
+	{
+	(void)aCategory;
+#ifdef BTRACE_KERNEL_MEMORY
+	// 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::EKernelMemory || (TInt)aCategory == -1)
+		{
+		BTrace4(BTrace::EKernelMemory,BTrace::EKernelMemoryInitialFree,TheSuperPage().iTotalRamSize);
+		BTrace4(BTrace::EKernelMemory,BTrace::EKernelMemoryCurrentFree,Kern::FreeRamInBytes());
+		}
+#endif
+	}
+
+/** 
+Restart the system. 
+On hardware targets this calls the Restart Vector in the ROM Header.
+Note, aMode is set to zero when this function is used by Kern::Fault()
+
+@param aMode Argument passed to the restart routine. The meaning of this value
+depends on the bootstrap implementation. 		
+*/
+EXPORT_C void Kern::Restart(TInt)
+	{
+	ExitProcess(0);
+	}
+
+EXPORT_C TInt TInternalRamDrive::MaxSize()
+	{
+	return PP::RamDriveMaxSize;
+	}
+
+void M::FsRegisterThread()
+	{
+	}
+
+void P::SetSuperPageSignature()
+	{
+	TUint32* sig = TheSuperPage().iSignature;
+	sig[0] = 0xb504f333;
+	sig[1] = 0xf9de6484;
+	}
+
+TBool P::CheckSuperPageSignature()
+	{
+	const TUint32* sig = TheSuperPage().iSignature;
+	return ( sig[0]==0xb504f333 && sig[1]==0xf9de6484 );
+	}
+
+// Dummy implementation of kernel pin APIs
+
+class TVirtualPinObject
+	{	
+	};
+
+TInt M::CreateVirtualPinObject(TVirtualPinObject*& aPinObject)
+	{
+	aPinObject = new TVirtualPinObject;
+	return aPinObject != NULL ? KErrNone : KErrNoMemory;
+	}
+
+TInt M::PinVirtualMemory(TVirtualPinObject* aPinObject, TLinAddr, TUint, DThread*)
+	{
+	__ASSERT_DEBUG(aPinObject, K::Fault(K::EVirtualPinObjectBad));
+	(void)aPinObject;
+	return KErrNone;
+	}
+
+TInt M::CreateAndPinVirtualMemory(TVirtualPinObject*& aPinObject, TLinAddr, TUint)
+	{
+	aPinObject = 0;
+	return KErrNone;
+	}
+
+void M::UnpinVirtualMemory(TVirtualPinObject* aPinObject)
+	{
+	__ASSERT_DEBUG(aPinObject, K::Fault(K::EVirtualPinObjectBad));
+	(void)aPinObject;
+	}
+
+void M::DestroyVirtualPinObject(TVirtualPinObject*& aPinObject)
+	{
+	TVirtualPinObject* object = (TVirtualPinObject*)__e32_atomic_swp_ord_ptr(&aPinObject, 0);
+	if (object)
+		Kern::AsyncFree(object);
+	}
+
+
+class TPhysicalPinObject
+	{	
+	};
+
+TInt M::CreatePhysicalPinObject(TPhysicalPinObject*& aPinObject)
+	{
+	aPinObject = new TPhysicalPinObject;
+	return aPinObject != NULL ? KErrNone : KErrNoMemory;
+	}
+
+TInt M::PinPhysicalMemory(TPhysicalPinObject* aPinObject, TLinAddr, TUint, TBool, TPhysAddr&, TPhysAddr*, TUint32&, TUint&, DThread*)
+	{
+	__ASSERT_DEBUG(aPinObject, K::Fault(K::EPhysicalPinObjectBad));
+	(void)aPinObject;
+	return KErrNone;
+	}
+
+void M::UnpinPhysicalMemory(TPhysicalPinObject* aPinObject)
+	{
+	__ASSERT_DEBUG(aPinObject, K::Fault(K::EPhysicalPinObjectBad));
+	(void)aPinObject;
+	}
+
+void M::DestroyPhysicalPinObject(TPhysicalPinObject*& aPinObject)
+	{
+	TPhysicalPinObject* object = (TPhysicalPinObject*)__e32_atomic_swp_ord_ptr(&aPinObject, 0);
+	if (object)
+		Kern::AsyncFree(object);
+	}
+
+// Misc DPagingDevice methods
+
+EXPORT_C void DPagingDevice::NotifyIdle()
+	{
+	// Not used on this memory model
+	}
+
+EXPORT_C void DPagingDevice::NotifyBusy()
+	{
+	// Not used on this memory model
+	}
+
+EXPORT_C TInt Cache::SyncPhysicalMemoryBeforeDmaWrite(TPhysAddr* , TUint , TUint , TUint , TUint32 )
+	{
+	CHECK_PRECONDITIONS(MASK_THREAD_STANDARD,"Cache::SyncPhysicalMemoryBeforeDmaWrite");
+	return KErrNotSupported;
+	}
+
+EXPORT_C TInt Cache::SyncPhysicalMemoryBeforeDmaRead(TPhysAddr* , TUint , TUint , TUint , TUint32 )
+	{
+	CHECK_PRECONDITIONS(MASK_THREAD_STANDARD,"Cache::SyncPhysicalMemoryBeforeDmaRead");
+	return KErrNotSupported;
+	}
+EXPORT_C TInt Cache::SyncPhysicalMemoryAfterDmaRead(TPhysAddr* , TUint , TUint , TUint , TUint32 )
+	{
+	CHECK_PRECONDITIONS(MASK_THREAD_STANDARD,"Cache::SyncPhysicalMemoryAfterDmaRead");
+	return KErrNotSupported;
+	}