diff -r 000000000000 -r 96e5fb8b040d kernel/eka/memmodel/emul/win32/mutils.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/memmodel/emul/win32/mutils.cpp Thu Dec 17 09:24:54 2009 +0200 @@ -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 +#include + +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(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; iiiDllData[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; iiiDllData[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; + }