sl@0: // Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of the License "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // sl@0: sl@0: #include sl@0: #include "mm.h" sl@0: #include "mmu.h" sl@0: sl@0: #include "maddressspace.h" sl@0: #include "mpdalloc.h" sl@0: #include "mmapping.h" sl@0: sl@0: sl@0: sl@0: /** sl@0: Allocator for OS Address Space IDs (OS ASIDs). sl@0: This is a simple bitmap allocator for KNumOsAsids integers with an sl@0: associated mutex to guard against concurrency when allocating and sl@0: freeing. sl@0: */ sl@0: class OsAsidAllocator sl@0: { sl@0: public: sl@0: void Init2() sl@0: { sl@0: iAllocator = TBitMapAllocator::New(KNumOsAsids,ETrue); sl@0: __NK_ASSERT_ALWAYS(iAllocator); sl@0: iAllocator->Alloc(KKernelOsAsid,1); // make kernel OS ASID already allocated sl@0: } sl@0: sl@0: TInt Alloc() sl@0: { sl@0: NKern::FMWait(&iLock); sl@0: TInt osAsid = iAllocator->Alloc(); sl@0: NKern::FMSignal(&iLock); sl@0: if(osAsid<0) sl@0: return KErrNoMemory; sl@0: return osAsid; sl@0: } sl@0: sl@0: void Free(TInt aOsAsid) sl@0: { sl@0: NKern::FMWait(&iLock); sl@0: iAllocator->Free(aOsAsid); sl@0: NKern::FMSignal(&iLock); sl@0: } sl@0: sl@0: private: sl@0: TBitMapAllocator* iAllocator; sl@0: NFastMutex iLock; sl@0: } sl@0: OsAsidAllocator; sl@0: sl@0: sl@0: // sl@0: // DAddressSpace sl@0: // sl@0: sl@0: DAddressSpace KernelAddressSpace; ///< The kernel's address space object. sl@0: sl@0: __ASSERT_COMPILE(KKernelOsAsid==0); sl@0: DAddressSpace* AddressSpace[KNumOsAsids] = { &KernelAddressSpace }; sl@0: sl@0: RVirtualAllocator DAddressSpace::UserGlobalVirtualAllocator; sl@0: RBackwardsVirtualAllocator DAddressSpace::UserCommonVirtualAllocator; sl@0: sl@0: /** sl@0: The read lock used for protecting the mappings container in address spaces (DAddressSpace::iMappings). sl@0: A single global lock is used for all processes - this isn't required but it is the simplest sl@0: implementation if we want to avoid the memory overhead of allocating a mutex per address space. sl@0: */ sl@0: NFastMutex TheAddressSpaceMappingLock; sl@0: sl@0: sl@0: /** sl@0: A pool of mutexes which are used to protect an address space's virtual address allocation sl@0: and acts as a write lock for the mappings container (DAddressSpace::iMappings). sl@0: */ sl@0: DMutexPool AddressSpaceMutexPool; sl@0: sl@0: sl@0: void DAddressSpace::Init2() sl@0: { sl@0: // create allocator for ASIDs... sl@0: OsAsidAllocator.Init2(); sl@0: sl@0: // construct the kernel's address space... sl@0: TInt r = KernelAddressSpace.Construct(0, KKernelSectionBase, KKernelSectionEnd); sl@0: __NK_ASSERT_ALWAYS(r==KErrNone); sl@0: sl@0: // mark primary i/o region as already allocated... sl@0: __ASSERT_COMPILE(((KPrimaryIOBase|KPrimaryIOEnd)&KChunkMask)==0); // region must be chunk aligned to avoid PDE type conflicts with any new allocations sl@0: TLinAddr addr; sl@0: TUint size; sl@0: r = KernelAddressSpace.AllocateVirtualMemory(addr,size,KPrimaryIOBase,KPrimaryIOEnd-KPrimaryIOBase,0); sl@0: __NK_ASSERT_ALWAYS(r==KErrNone); sl@0: sl@0: // construct user global memory allocator... sl@0: r = UserGlobalVirtualAllocator.Construct(KGlobalMemoryBase,KUserMemoryLimit,ENumVirtualAllocTypes,AddressSpace[KKernelOsAsid]->iLock); sl@0: __NK_ASSERT_ALWAYS(r==KErrNone); sl@0: sl@0: // construct user common memory allocator (two slab types, one each for paged and unpaged memory)... sl@0: r = UserCommonVirtualAllocator.Construct(KUserLocalDataBase,KUserLocalDataEnd,ENumVirtualAllocTypes,AddressSpace[KKernelOsAsid]->iLock); sl@0: __NK_ASSERT_ALWAYS(r==KErrNone); sl@0: sl@0: // reserve virtual memory for XIP user code... sl@0: TUint romDataSize = TheRomHeader().iTotalUserDataSize; sl@0: TLinAddr romDataBase = TheRomHeader().iUserDataAddress-romDataSize; sl@0: __NK_ASSERT_DEBUG(TheRomHeader().iUserDataAddress==KUserLocalDataEnd); sl@0: if(romDataSize) sl@0: { sl@0: r = UserCommonVirtualAllocator.Alloc(addr,size,romDataBase,romDataSize,0); sl@0: __NK_ASSERT_ALWAYS(r==KErrNone); sl@0: } sl@0: } sl@0: sl@0: sl@0: DAddressSpace::DAddressSpace() sl@0: : iMappings(&TheAddressSpaceMappingLock,iLock) sl@0: { sl@0: } sl@0: sl@0: sl@0: TInt DAddressSpace::New(TPhysAddr& aPageDirectory) sl@0: { sl@0: TRACE(("DAddressSpace::New(?)")); sl@0: TInt r; sl@0: TInt osAsid = OsAsidAllocator.Alloc(); sl@0: if(osAsid<0) sl@0: r = KErrNoMemory; sl@0: else sl@0: { sl@0: r = PageDirectories.Alloc(osAsid,aPageDirectory); sl@0: if(r!=KErrNone) sl@0: OsAsidAllocator.Free(osAsid); sl@0: else sl@0: { sl@0: DAddressSpace*& info = AddressSpace[osAsid]; sl@0: __NK_ASSERT_DEBUG(!info); sl@0: info = new DAddressSpace(); sl@0: if(!info) sl@0: { sl@0: PageDirectories.Free(osAsid); sl@0: OsAsidAllocator.Free(osAsid); sl@0: r = KErrNoMemory; sl@0: } sl@0: else sl@0: { sl@0: r = info->Construct(osAsid,KUserLocalDataBase,KUserLocalDataEnd); sl@0: if(r!=KErrNone) sl@0: { sl@0: info->Close(); sl@0: info = 0; sl@0: } sl@0: } sl@0: } sl@0: } sl@0: sl@0: if(r==KErrNone) sl@0: r = osAsid; sl@0: else sl@0: aPageDirectory = KPhysAddrInvalid; sl@0: sl@0: TRACE(("DAddressSpace::New returns %d",r)); sl@0: return r; sl@0: } sl@0: sl@0: sl@0: sl@0: DAddressSpace::~DAddressSpace() sl@0: { sl@0: TRACE(("DAddressSpace[0x%08x]::~DAddressSpace() osAsid = %d",this,iOsAsid)); sl@0: #ifdef _DEBUG sl@0: if(iMappings.Count()) sl@0: Dump(); sl@0: #endif sl@0: __NK_ASSERT_DEBUG(iMappings.Count()==0); sl@0: sl@0: TInt osAsid = iOsAsid; sl@0: AddressSpace[osAsid] = 0; sl@0: PageDirectories.Free(osAsid); sl@0: InvalidateTLBForAsid(osAsid); sl@0: OsAsidAllocator.Free(osAsid); sl@0: } sl@0: sl@0: sl@0: TInt DAddressSpace::Construct(TInt aOsAsid, TLinAddr aStart, TLinAddr aEnd) sl@0: { sl@0: TRACE(("DAddressSpace::Construct(%d,0x%08x,0x%08x)",aOsAsid,aStart,aEnd)); sl@0: iOsAsid = aOsAsid; sl@0: return iVirtualAllocator.Construct(aStart,aEnd,ENumVirtualAllocTypes,iLock); sl@0: } sl@0: sl@0: sl@0: void DAddressSpace::Lock() sl@0: { sl@0: AddressSpaceMutexPool.Wait(iLock); sl@0: } sl@0: sl@0: sl@0: void DAddressSpace::Unlock() sl@0: { sl@0: AddressSpaceMutexPool.Signal(iLock); sl@0: } sl@0: sl@0: sl@0: TInt DAddressSpace::AllocateVirtualMemory(TLinAddr& aAddr, TUint& aSize, TLinAddr aRequestedAddr, TUint aRequestedSize, TUint aPdeType) sl@0: { sl@0: TRACE(("DAddressSpace::AllocateVirtualMemory(?,?,0x%08x,0x%08x,%d) osAsid=%d",aRequestedAddr,aRequestedSize,aPdeType,iOsAsid)); sl@0: __NK_ASSERT_DEBUG(aPdeTypeIsAttached()) sl@0: { sl@0: // found mapping, check addresses are in range... sl@0: TUint offset = aAddr-mapping->Base(); sl@0: TUint end = offset+aSize; sl@0: if(offsetiSizeInPages<MapInstanceCount(); sl@0: mapping->Open(); // can't fail because mapping IsAttached sl@0: result = mapping; sl@0: } sl@0: } sl@0: iMappings.ReadUnlock(); sl@0: sl@0: return result; sl@0: } sl@0: sl@0: sl@0: TBool DAddressSpace::CheckPdeType(TLinAddr aAddr, TUint aSize, TUint aPdeType) sl@0: { sl@0: TRACE(("DAddressSpace::CheckPdeType(0x%08x,0x%08x,%d) osAsid=%d",aAddr, aSize, aPdeType, iOsAsid)); sl@0: TBool r; sl@0: Lock(); sl@0: if(iOsAsid==(TInt)KKernelOsAsid && UserGlobalVirtualAllocator.InRange(aAddr,aSize)) sl@0: r = UserGlobalVirtualAllocator.CheckSlabType(aAddr,aSize,aPdeType); sl@0: else sl@0: r = iVirtualAllocator.CheckSlabType(aAddr,aSize,aPdeType); sl@0: TRACE(("DAddressSpace::CheckPdeType returns %d",r)); sl@0: Unlock(); sl@0: return r; sl@0: } sl@0: sl@0: sl@0: sl@0: // sl@0: // Debug sl@0: // sl@0: sl@0: #ifdef _DEBUG sl@0: sl@0: void DAddressSpace::Dump() sl@0: { sl@0: Kern::Printf("DAddressSpace[0x%08x]::Dump() osAsid = %d",this,iOsAsid); sl@0: TLinAddr virt = 0; sl@0: do sl@0: { sl@0: --virt; sl@0: iMappings.ReadLock(); sl@0: TUint offsetInMapping = 0; sl@0: DMemoryMapping* mapping = (DMemoryMapping*)iMappings.Find(virt,offsetInMapping); sl@0: if(mapping) sl@0: { sl@0: if(!mapping->TryOpen()) sl@0: mapping = NULL; sl@0: virt -= offsetInMapping; sl@0: } sl@0: iMappings.ReadUnlock(); sl@0: if(!mapping) sl@0: break; sl@0: mapping->Dump(); sl@0: mapping->Close(); sl@0: } sl@0: while(virt); sl@0: } sl@0: sl@0: #endif // _DEBUG