1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/kernel/eka/memmodel/epoc/flexible/mmu/maddressspace.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,389 @@
1.4 +// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of the License "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +//
1.18 +
1.19 +#include <plat_priv.h>
1.20 +#include "mm.h"
1.21 +#include "mmu.h"
1.22 +
1.23 +#include "maddressspace.h"
1.24 +#include "mpdalloc.h"
1.25 +#include "mmapping.h"
1.26 +
1.27 +
1.28 +
1.29 +/**
1.30 +Allocator for OS Address Space IDs (OS ASIDs).
1.31 +This is a simple bitmap allocator for KNumOsAsids integers with an
1.32 +associated mutex to guard against concurrency when allocating and
1.33 +freeing.
1.34 +*/
1.35 +class OsAsidAllocator
1.36 + {
1.37 +public:
1.38 + void Init2()
1.39 + {
1.40 + iAllocator = TBitMapAllocator::New(KNumOsAsids,ETrue);
1.41 + __NK_ASSERT_ALWAYS(iAllocator);
1.42 + iAllocator->Alloc(KKernelOsAsid,1); // make kernel OS ASID already allocated
1.43 + }
1.44 +
1.45 + TInt Alloc()
1.46 + {
1.47 + NKern::FMWait(&iLock);
1.48 + TInt osAsid = iAllocator->Alloc();
1.49 + NKern::FMSignal(&iLock);
1.50 + if(osAsid<0)
1.51 + return KErrNoMemory;
1.52 + return osAsid;
1.53 + }
1.54 +
1.55 + void Free(TInt aOsAsid)
1.56 + {
1.57 + NKern::FMWait(&iLock);
1.58 + iAllocator->Free(aOsAsid);
1.59 + NKern::FMSignal(&iLock);
1.60 + }
1.61 +
1.62 +private:
1.63 + TBitMapAllocator* iAllocator;
1.64 + NFastMutex iLock;
1.65 + }
1.66 +OsAsidAllocator;
1.67 +
1.68 +
1.69 +//
1.70 +// DAddressSpace
1.71 +//
1.72 +
1.73 +DAddressSpace KernelAddressSpace; ///< The kernel's address space object.
1.74 +
1.75 +__ASSERT_COMPILE(KKernelOsAsid==0);
1.76 +DAddressSpace* AddressSpace[KNumOsAsids] = { &KernelAddressSpace };
1.77 +
1.78 +RVirtualAllocator DAddressSpace::UserGlobalVirtualAllocator;
1.79 +RBackwardsVirtualAllocator DAddressSpace::UserCommonVirtualAllocator;
1.80 +
1.81 +/**
1.82 +The read lock used for protecting the mappings container in address spaces (DAddressSpace::iMappings).
1.83 +A single global lock is used for all processes - this isn't required but it is the simplest
1.84 +implementation if we want to avoid the memory overhead of allocating a mutex per address space.
1.85 +*/
1.86 +NFastMutex TheAddressSpaceMappingLock;
1.87 +
1.88 +
1.89 +/**
1.90 +A pool of mutexes which are used to protect an address space's virtual address allocation
1.91 +and acts as a write lock for the mappings container (DAddressSpace::iMappings).
1.92 +*/
1.93 +DMutexPool AddressSpaceMutexPool;
1.94 +
1.95 +
1.96 +void DAddressSpace::Init2()
1.97 + {
1.98 + // create allocator for ASIDs...
1.99 + OsAsidAllocator.Init2();
1.100 +
1.101 + // construct the kernel's address space...
1.102 + TInt r = KernelAddressSpace.Construct(0, KKernelSectionBase, KKernelSectionEnd);
1.103 + __NK_ASSERT_ALWAYS(r==KErrNone);
1.104 +
1.105 + // mark primary i/o region as already allocated...
1.106 + __ASSERT_COMPILE(((KPrimaryIOBase|KPrimaryIOEnd)&KChunkMask)==0); // region must be chunk aligned to avoid PDE type conflicts with any new allocations
1.107 + TLinAddr addr;
1.108 + TUint size;
1.109 + r = KernelAddressSpace.AllocateVirtualMemory(addr,size,KPrimaryIOBase,KPrimaryIOEnd-KPrimaryIOBase,0);
1.110 + __NK_ASSERT_ALWAYS(r==KErrNone);
1.111 +
1.112 + // construct user global memory allocator...
1.113 + r = UserGlobalVirtualAllocator.Construct(KGlobalMemoryBase,KUserMemoryLimit,ENumVirtualAllocTypes,AddressSpace[KKernelOsAsid]->iLock);
1.114 + __NK_ASSERT_ALWAYS(r==KErrNone);
1.115 +
1.116 + // construct user common memory allocator (two slab types, one each for paged and unpaged memory)...
1.117 + r = UserCommonVirtualAllocator.Construct(KUserLocalDataBase,KUserLocalDataEnd,ENumVirtualAllocTypes,AddressSpace[KKernelOsAsid]->iLock);
1.118 + __NK_ASSERT_ALWAYS(r==KErrNone);
1.119 +
1.120 + // reserve virtual memory for XIP user code...
1.121 + TUint romDataSize = TheRomHeader().iTotalUserDataSize;
1.122 + TLinAddr romDataBase = TheRomHeader().iUserDataAddress-romDataSize;
1.123 + __NK_ASSERT_DEBUG(TheRomHeader().iUserDataAddress==KUserLocalDataEnd);
1.124 + if(romDataSize)
1.125 + {
1.126 + r = UserCommonVirtualAllocator.Alloc(addr,size,romDataBase,romDataSize,0);
1.127 + __NK_ASSERT_ALWAYS(r==KErrNone);
1.128 + }
1.129 + }
1.130 +
1.131 +
1.132 +DAddressSpace::DAddressSpace()
1.133 + : iMappings(&TheAddressSpaceMappingLock,iLock)
1.134 + {
1.135 + }
1.136 +
1.137 +
1.138 +TInt DAddressSpace::New(TPhysAddr& aPageDirectory)
1.139 + {
1.140 + TRACE(("DAddressSpace::New(?)"));
1.141 + TInt r;
1.142 + TInt osAsid = OsAsidAllocator.Alloc();
1.143 + if(osAsid<0)
1.144 + r = KErrNoMemory;
1.145 + else
1.146 + {
1.147 + r = PageDirectories.Alloc(osAsid,aPageDirectory);
1.148 + if(r!=KErrNone)
1.149 + OsAsidAllocator.Free(osAsid);
1.150 + else
1.151 + {
1.152 + DAddressSpace*& info = AddressSpace[osAsid];
1.153 + __NK_ASSERT_DEBUG(!info);
1.154 + info = new DAddressSpace();
1.155 + if(!info)
1.156 + {
1.157 + PageDirectories.Free(osAsid);
1.158 + OsAsidAllocator.Free(osAsid);
1.159 + r = KErrNoMemory;
1.160 + }
1.161 + else
1.162 + {
1.163 + r = info->Construct(osAsid,KUserLocalDataBase,KUserLocalDataEnd);
1.164 + if(r!=KErrNone)
1.165 + {
1.166 + info->Close();
1.167 + info = 0;
1.168 + }
1.169 + }
1.170 + }
1.171 + }
1.172 +
1.173 + if(r==KErrNone)
1.174 + r = osAsid;
1.175 + else
1.176 + aPageDirectory = KPhysAddrInvalid;
1.177 +
1.178 + TRACE(("DAddressSpace::New returns %d",r));
1.179 + return r;
1.180 + }
1.181 +
1.182 +
1.183 +
1.184 +DAddressSpace::~DAddressSpace()
1.185 + {
1.186 + TRACE(("DAddressSpace[0x%08x]::~DAddressSpace() osAsid = %d",this,iOsAsid));
1.187 +#ifdef _DEBUG
1.188 + if(iMappings.Count())
1.189 + Dump();
1.190 +#endif
1.191 + __NK_ASSERT_DEBUG(iMappings.Count()==0);
1.192 +
1.193 + TInt osAsid = iOsAsid;
1.194 + AddressSpace[osAsid] = 0;
1.195 + PageDirectories.Free(osAsid);
1.196 + InvalidateTLBForAsid(osAsid);
1.197 + OsAsidAllocator.Free(osAsid);
1.198 + }
1.199 +
1.200 +
1.201 +TInt DAddressSpace::Construct(TInt aOsAsid, TLinAddr aStart, TLinAddr aEnd)
1.202 + {
1.203 + TRACE(("DAddressSpace::Construct(%d,0x%08x,0x%08x)",aOsAsid,aStart,aEnd));
1.204 + iOsAsid = aOsAsid;
1.205 + return iVirtualAllocator.Construct(aStart,aEnd,ENumVirtualAllocTypes,iLock);
1.206 + }
1.207 +
1.208 +
1.209 +void DAddressSpace::Lock()
1.210 + {
1.211 + AddressSpaceMutexPool.Wait(iLock);
1.212 + }
1.213 +
1.214 +
1.215 +void DAddressSpace::Unlock()
1.216 + {
1.217 + AddressSpaceMutexPool.Signal(iLock);
1.218 + }
1.219 +
1.220 +
1.221 +TInt DAddressSpace::AllocateVirtualMemory(TLinAddr& aAddr, TUint& aSize, TLinAddr aRequestedAddr, TUint aRequestedSize, TUint aPdeType)
1.222 + {
1.223 + TRACE(("DAddressSpace::AllocateVirtualMemory(?,?,0x%08x,0x%08x,%d) osAsid=%d",aRequestedAddr,aRequestedSize,aPdeType,iOsAsid));
1.224 + __NK_ASSERT_DEBUG(aPdeType<ENumVirtualAllocTypes);
1.225 + Lock();
1.226 + TInt r = iVirtualAllocator.Alloc(aAddr,aSize,aRequestedAddr,aRequestedSize,aPdeType);
1.227 + if(r==KErrNone)
1.228 + Open();
1.229 + Unlock();
1.230 + TRACE(("DAddressSpace::AllocateVirtualMemory returns %d region=0x%08x+0x%08x",r,aAddr,aSize));
1.231 + return r;
1.232 + }
1.233 +
1.234 +
1.235 +TInt DAddressSpace::AllocateUserGlobalVirtualMemory(TLinAddr& aAddr, TUint& aSize, TLinAddr aRequestedAddr, TUint aRequestedSize, TUint aPdeType)
1.236 + {
1.237 + TRACE(("DAddressSpace::AllocateUserGlobalVirtualMemory(?,?,0x%08x,0x%08x,%d)",aRequestedAddr,aRequestedSize,aPdeType));
1.238 + __NK_ASSERT_DEBUG(aPdeType<ENumVirtualAllocTypes);
1.239 + KernelAddressSpace.Lock();
1.240 + TInt r = UserGlobalVirtualAllocator.Alloc(aAddr,aSize,aRequestedAddr,aRequestedSize,aPdeType);
1.241 + KernelAddressSpace.Unlock();
1.242 + TRACE(("DAddressSpace::AllocateUserGlobalVirtualMemory returns %d region=0x%08x+0x%08x",r,aAddr,aSize));
1.243 + return r;
1.244 + }
1.245 +
1.246 +
1.247 +void DAddressSpace::FreeVirtualMemory(TLinAddr aAddr, TUint aSize)
1.248 + {
1.249 + TRACE(("DAddressSpace::FreeVirtualMemory(0x%08x,0x%08x) osAsid=%d",aAddr, aSize, iOsAsid));
1.250 + Lock();
1.251 + if(iOsAsid==(TInt)KKernelOsAsid && UserGlobalVirtualAllocator.InRange(aAddr,aSize))
1.252 + UserGlobalVirtualAllocator.Free(aAddr,aSize);
1.253 + else
1.254 + {
1.255 + iVirtualAllocator.Free(aAddr,aSize);
1.256 + AsyncClose();
1.257 + }
1.258 + Unlock();
1.259 + }
1.260 +
1.261 +
1.262 +TInt DAddressSpace::AllocateUserCommonVirtualMemory(TLinAddr& aAddr, TUint& aSize, TLinAddr aRequestedAddr, TUint aRequestedSize, TUint aPdeType)
1.263 + {
1.264 + TRACE(("DAddressSpace::AllocateUserCommonVirtualMemory(?,?,0x%08x,0x%08x,%d)",aRequestedAddr,aRequestedSize,aPdeType));
1.265 + __NK_ASSERT_DEBUG(aPdeType<ENumVirtualAllocTypes);
1.266 + KernelAddressSpace.Lock();
1.267 + TInt r = UserCommonVirtualAllocator.Alloc(aAddr,aSize,aRequestedAddr,aRequestedSize,aPdeType);
1.268 + KernelAddressSpace.Unlock();
1.269 + TRACE(("DAddressSpace::AllocateUserCommonVirtualMemory returns %d region=0x%08x+0x%08x",r,aAddr,aSize));
1.270 + return r;
1.271 + }
1.272 +
1.273 +
1.274 +void DAddressSpace::FreeUserCommonVirtualMemory(TLinAddr aAddr, TUint aSize)
1.275 + {
1.276 + TRACE(("DAddressSpace::FreeUserCommonVirtualMemory(0x%08x,0x%08x)",aAddr,aSize));
1.277 + KernelAddressSpace.Lock();
1.278 + UserCommonVirtualAllocator.Free(aAddr,aSize);
1.279 + KernelAddressSpace.Unlock();
1.280 + }
1.281 +
1.282 +
1.283 +TInt DAddressSpace::AddMapping(TLinAddr aAddr, DMemoryMapping* aMapping)
1.284 + {
1.285 + Lock();
1.286 + TRACE(("DAddressSpace::AddMapping(0x%08x,0x%08x) osAsid=%d",aAddr, aMapping, iOsAsid));
1.287 + TInt r = iMappings.Add(aAddr,aMapping);
1.288 + TRACE(("DAddressSpace::AddMapping osAsid=%d returns %d",iOsAsid, r));
1.289 + Unlock();
1.290 + return r;
1.291 + }
1.292 +
1.293 +
1.294 +DMemoryMapping* DAddressSpace::RemoveMapping(TLinAddr aAddr)
1.295 + {
1.296 + Lock();
1.297 + DMemoryMapping* removed = (DMemoryMapping*)iMappings.Remove(aAddr);
1.298 + TRACE(("DAddressSpace::RemoveMapping(0x%08x) osAsid=%d returns 0x%08x",aAddr, iOsAsid, removed));
1.299 + Unlock();
1.300 + return removed;
1.301 + }
1.302 +
1.303 +
1.304 +DMemoryMapping* DAddressSpace::GetMapping(TLinAddr aAddr)
1.305 + {
1.306 + iMappings.ReadLock();
1.307 + DMemoryMapping* mapping = (DMemoryMapping*)iMappings.Find(aAddr);
1.308 + TRACE(("DAddressSpace::GetMapping(0x%08x) osAsid=%d returns 0x%08x",aAddr, iOsAsid, mapping));
1.309 + __NK_ASSERT_DEBUG(mapping); // caller must know there is a mapping
1.310 + iMappings.ReadUnlock();
1.311 + return mapping;
1.312 + }
1.313 +
1.314 +
1.315 +DMemoryMapping* DAddressSpace::FindMapping(TLinAddr aAddr, TUint aSize, TUint& aOffsetInMapping, TUint& aInstanceCount)
1.316 + {
1.317 + __ASSERT_CRITICAL;
1.318 +
1.319 + DMemoryMapping* result = NULL;
1.320 +
1.321 + // find mapping...
1.322 + iMappings.ReadLock();
1.323 + TUint dummy;
1.324 + DMemoryMapping* mapping = (DMemoryMapping*)iMappings.Find(aAddr,dummy);
1.325 + if(mapping && mapping->IsAttached())
1.326 + {
1.327 + // found mapping, check addresses are in range...
1.328 + TUint offset = aAddr-mapping->Base();
1.329 + TUint end = offset+aSize;
1.330 + if(offset<end && end<=mapping->iSizeInPages<<KPageShift)
1.331 + {
1.332 + // addresses OK, get a reference on the mapping before releasing list lock...
1.333 + aOffsetInMapping = offset;
1.334 + aInstanceCount = mapping->MapInstanceCount();
1.335 + mapping->Open(); // can't fail because mapping IsAttached
1.336 + result = mapping;
1.337 + }
1.338 + }
1.339 + iMappings.ReadUnlock();
1.340 +
1.341 + return result;
1.342 + }
1.343 +
1.344 +
1.345 +TBool DAddressSpace::CheckPdeType(TLinAddr aAddr, TUint aSize, TUint aPdeType)
1.346 + {
1.347 + TRACE(("DAddressSpace::CheckPdeType(0x%08x,0x%08x,%d) osAsid=%d",aAddr, aSize, aPdeType, iOsAsid));
1.348 + TBool r;
1.349 + Lock();
1.350 + if(iOsAsid==(TInt)KKernelOsAsid && UserGlobalVirtualAllocator.InRange(aAddr,aSize))
1.351 + r = UserGlobalVirtualAllocator.CheckSlabType(aAddr,aSize,aPdeType);
1.352 + else
1.353 + r = iVirtualAllocator.CheckSlabType(aAddr,aSize,aPdeType);
1.354 + TRACE(("DAddressSpace::CheckPdeType returns %d",r));
1.355 + Unlock();
1.356 + return r;
1.357 + }
1.358 +
1.359 +
1.360 +
1.361 +//
1.362 +// Debug
1.363 +//
1.364 +
1.365 +#ifdef _DEBUG
1.366 +
1.367 +void DAddressSpace::Dump()
1.368 + {
1.369 + Kern::Printf("DAddressSpace[0x%08x]::Dump() osAsid = %d",this,iOsAsid);
1.370 + TLinAddr virt = 0;
1.371 + do
1.372 + {
1.373 + --virt;
1.374 + iMappings.ReadLock();
1.375 + TUint offsetInMapping = 0;
1.376 + DMemoryMapping* mapping = (DMemoryMapping*)iMappings.Find(virt,offsetInMapping);
1.377 + if(mapping)
1.378 + {
1.379 + if(!mapping->TryOpen())
1.380 + mapping = NULL;
1.381 + virt -= offsetInMapping;
1.382 + }
1.383 + iMappings.ReadUnlock();
1.384 + if(!mapping)
1.385 + break;
1.386 + mapping->Dump();
1.387 + mapping->Close();
1.388 + }
1.389 + while(virt);
1.390 + }
1.391 +
1.392 +#endif // _DEBUG