Fix for bug 2283 (RVCT 4.0 support is missing from PDK 3.0.h)
Have multiple extension sections in the bld.inf, one for each version
of the compiler. The RVCT version building the tools will build the
runtime libraries for its version, but make sure we extract all the other
versions from zip archives. Also add the archive for RVCT4.
// Copyright (c) 2007-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:
//
#include <plat_priv.h>
#include "mm.h"
#include "mmu.h"
#include "maddressspace.h"
#include "mpdalloc.h"
#include "mmapping.h"
/**
Allocator for OS Address Space IDs (OS ASIDs).
This is a simple bitmap allocator for KNumOsAsids integers with an
associated mutex to guard against concurrency when allocating and
freeing.
*/
class OsAsidAllocator
{
public:
void Init2()
{
iAllocator = TBitMapAllocator::New(KNumOsAsids,ETrue);
__NK_ASSERT_ALWAYS(iAllocator);
iAllocator->Alloc(KKernelOsAsid,1); // make kernel OS ASID already allocated
}
TInt Alloc()
{
NKern::FMWait(&iLock);
TInt osAsid = iAllocator->Alloc();
NKern::FMSignal(&iLock);
if(osAsid<0)
return KErrNoMemory;
return osAsid;
}
void Free(TInt aOsAsid)
{
NKern::FMWait(&iLock);
iAllocator->Free(aOsAsid);
NKern::FMSignal(&iLock);
}
private:
TBitMapAllocator* iAllocator;
NFastMutex iLock;
}
OsAsidAllocator;
//
// DAddressSpace
//
DAddressSpace KernelAddressSpace; ///< The kernel's address space object.
__ASSERT_COMPILE(KKernelOsAsid==0);
DAddressSpace* AddressSpace[KNumOsAsids] = { &KernelAddressSpace };
RVirtualAllocator DAddressSpace::UserGlobalVirtualAllocator;
RBackwardsVirtualAllocator DAddressSpace::UserCommonVirtualAllocator;
/**
The read lock used for protecting the mappings container in address spaces (DAddressSpace::iMappings).
A single global lock is used for all processes - this isn't required but it is the simplest
implementation if we want to avoid the memory overhead of allocating a mutex per address space.
*/
NFastMutex TheAddressSpaceMappingLock;
/**
A pool of mutexes which are used to protect an address space's virtual address allocation
and acts as a write lock for the mappings container (DAddressSpace::iMappings).
*/
DMutexPool AddressSpaceMutexPool;
void DAddressSpace::Init2()
{
// create allocator for ASIDs...
OsAsidAllocator.Init2();
// construct the kernel's address space...
TInt r = KernelAddressSpace.Construct(0, KKernelSectionBase, KKernelSectionEnd);
__NK_ASSERT_ALWAYS(r==KErrNone);
// mark primary i/o region as already allocated...
__ASSERT_COMPILE(((KPrimaryIOBase|KPrimaryIOEnd)&KChunkMask)==0); // region must be chunk aligned to avoid PDE type conflicts with any new allocations
TLinAddr addr;
TUint size;
r = KernelAddressSpace.AllocateVirtualMemory(addr,size,KPrimaryIOBase,KPrimaryIOEnd-KPrimaryIOBase,0);
__NK_ASSERT_ALWAYS(r==KErrNone);
// construct user global memory allocator...
r = UserGlobalVirtualAllocator.Construct(KGlobalMemoryBase,KUserMemoryLimit,ENumVirtualAllocTypes,AddressSpace[KKernelOsAsid]->iLock);
__NK_ASSERT_ALWAYS(r==KErrNone);
// construct user common memory allocator (two slab types, one each for paged and unpaged memory)...
r = UserCommonVirtualAllocator.Construct(KUserLocalDataBase,KUserLocalDataEnd,ENumVirtualAllocTypes,AddressSpace[KKernelOsAsid]->iLock);
__NK_ASSERT_ALWAYS(r==KErrNone);
// reserve virtual memory for XIP user code...
TUint romDataSize = TheRomHeader().iTotalUserDataSize;
TLinAddr romDataBase = TheRomHeader().iUserDataAddress-romDataSize;
__NK_ASSERT_DEBUG(TheRomHeader().iUserDataAddress==KUserLocalDataEnd);
if(romDataSize)
{
r = UserCommonVirtualAllocator.Alloc(addr,size,romDataBase,romDataSize,0);
__NK_ASSERT_ALWAYS(r==KErrNone);
}
}
DAddressSpace::DAddressSpace()
: iMappings(&TheAddressSpaceMappingLock,iLock)
{
}
TInt DAddressSpace::New(TPhysAddr& aPageDirectory)
{
TRACE(("DAddressSpace::New(?)"));
TInt r;
TInt osAsid = OsAsidAllocator.Alloc();
if(osAsid<0)
r = KErrNoMemory;
else
{
r = PageDirectories.Alloc(osAsid,aPageDirectory);
if(r!=KErrNone)
OsAsidAllocator.Free(osAsid);
else
{
DAddressSpace*& info = AddressSpace[osAsid];
__NK_ASSERT_DEBUG(!info);
info = new DAddressSpace();
if(!info)
{
PageDirectories.Free(osAsid);
OsAsidAllocator.Free(osAsid);
r = KErrNoMemory;
}
else
{
r = info->Construct(osAsid,KUserLocalDataBase,KUserLocalDataEnd);
if(r!=KErrNone)
{
info->Close();
info = 0;
}
}
}
}
if(r==KErrNone)
r = osAsid;
else
aPageDirectory = KPhysAddrInvalid;
TRACE(("DAddressSpace::New returns %d",r));
return r;
}
DAddressSpace::~DAddressSpace()
{
TRACE(("DAddressSpace[0x%08x]::~DAddressSpace() osAsid = %d",this,iOsAsid));
#ifdef _DEBUG
if(iMappings.Count())
Dump();
#endif
__NK_ASSERT_DEBUG(iMappings.Count()==0);
TInt osAsid = iOsAsid;
AddressSpace[osAsid] = 0;
PageDirectories.Free(osAsid);
InvalidateTLBForAsid(osAsid);
OsAsidAllocator.Free(osAsid);
}
TInt DAddressSpace::Construct(TInt aOsAsid, TLinAddr aStart, TLinAddr aEnd)
{
TRACE(("DAddressSpace::Construct(%d,0x%08x,0x%08x)",aOsAsid,aStart,aEnd));
iOsAsid = aOsAsid;
return iVirtualAllocator.Construct(aStart,aEnd,ENumVirtualAllocTypes,iLock);
}
void DAddressSpace::Lock()
{
AddressSpaceMutexPool.Wait(iLock);
}
void DAddressSpace::Unlock()
{
AddressSpaceMutexPool.Signal(iLock);
}
TInt DAddressSpace::AllocateVirtualMemory(TLinAddr& aAddr, TUint& aSize, TLinAddr aRequestedAddr, TUint aRequestedSize, TUint aPdeType)
{
TRACE(("DAddressSpace::AllocateVirtualMemory(?,?,0x%08x,0x%08x,%d) osAsid=%d",aRequestedAddr,aRequestedSize,aPdeType,iOsAsid));
__NK_ASSERT_DEBUG(aPdeType<ENumVirtualAllocTypes);
Lock();
TInt r = iVirtualAllocator.Alloc(aAddr,aSize,aRequestedAddr,aRequestedSize,aPdeType);
if(r==KErrNone)
Open();
Unlock();
TRACE(("DAddressSpace::AllocateVirtualMemory returns %d region=0x%08x+0x%08x",r,aAddr,aSize));
return r;
}
TInt DAddressSpace::AllocateUserGlobalVirtualMemory(TLinAddr& aAddr, TUint& aSize, TLinAddr aRequestedAddr, TUint aRequestedSize, TUint aPdeType)
{
TRACE(("DAddressSpace::AllocateUserGlobalVirtualMemory(?,?,0x%08x,0x%08x,%d)",aRequestedAddr,aRequestedSize,aPdeType));
__NK_ASSERT_DEBUG(aPdeType<ENumVirtualAllocTypes);
KernelAddressSpace.Lock();
TInt r = UserGlobalVirtualAllocator.Alloc(aAddr,aSize,aRequestedAddr,aRequestedSize,aPdeType);
KernelAddressSpace.Unlock();
TRACE(("DAddressSpace::AllocateUserGlobalVirtualMemory returns %d region=0x%08x+0x%08x",r,aAddr,aSize));
return r;
}
void DAddressSpace::FreeVirtualMemory(TLinAddr aAddr, TUint aSize)
{
TRACE(("DAddressSpace::FreeVirtualMemory(0x%08x,0x%08x) osAsid=%d",aAddr, aSize, iOsAsid));
Lock();
if(iOsAsid==(TInt)KKernelOsAsid && UserGlobalVirtualAllocator.InRange(aAddr,aSize))
UserGlobalVirtualAllocator.Free(aAddr,aSize);
else
{
iVirtualAllocator.Free(aAddr,aSize);
AsyncClose();
}
Unlock();
}
TInt DAddressSpace::AllocateUserCommonVirtualMemory(TLinAddr& aAddr, TUint& aSize, TLinAddr aRequestedAddr, TUint aRequestedSize, TUint aPdeType)
{
TRACE(("DAddressSpace::AllocateUserCommonVirtualMemory(?,?,0x%08x,0x%08x,%d)",aRequestedAddr,aRequestedSize,aPdeType));
__NK_ASSERT_DEBUG(aPdeType<ENumVirtualAllocTypes);
KernelAddressSpace.Lock();
TInt r = UserCommonVirtualAllocator.Alloc(aAddr,aSize,aRequestedAddr,aRequestedSize,aPdeType);
KernelAddressSpace.Unlock();
TRACE(("DAddressSpace::AllocateUserCommonVirtualMemory returns %d region=0x%08x+0x%08x",r,aAddr,aSize));
return r;
}
void DAddressSpace::FreeUserCommonVirtualMemory(TLinAddr aAddr, TUint aSize)
{
TRACE(("DAddressSpace::FreeUserCommonVirtualMemory(0x%08x,0x%08x)",aAddr,aSize));
KernelAddressSpace.Lock();
UserCommonVirtualAllocator.Free(aAddr,aSize);
KernelAddressSpace.Unlock();
}
TInt DAddressSpace::AddMapping(TLinAddr aAddr, DMemoryMapping* aMapping)
{
Lock();
TRACE(("DAddressSpace::AddMapping(0x%08x,0x%08x) osAsid=%d",aAddr, aMapping, iOsAsid));
TInt r = iMappings.Add(aAddr,aMapping);
TRACE(("DAddressSpace::AddMapping osAsid=%d returns %d",iOsAsid, r));
Unlock();
return r;
}
DMemoryMapping* DAddressSpace::RemoveMapping(TLinAddr aAddr)
{
Lock();
DMemoryMapping* removed = (DMemoryMapping*)iMappings.Remove(aAddr);
TRACE(("DAddressSpace::RemoveMapping(0x%08x) osAsid=%d returns 0x%08x",aAddr, iOsAsid, removed));
Unlock();
return removed;
}
DMemoryMapping* DAddressSpace::GetMapping(TLinAddr aAddr)
{
iMappings.ReadLock();
DMemoryMapping* mapping = (DMemoryMapping*)iMappings.Find(aAddr);
TRACE(("DAddressSpace::GetMapping(0x%08x) osAsid=%d returns 0x%08x",aAddr, iOsAsid, mapping));
__NK_ASSERT_DEBUG(mapping); // caller must know there is a mapping
iMappings.ReadUnlock();
return mapping;
}
DMemoryMapping* DAddressSpace::FindMapping(TLinAddr aAddr, TUint aSize, TUint& aOffsetInMapping, TUint& aInstanceCount)
{
__ASSERT_CRITICAL;
DMemoryMapping* result = NULL;
// find mapping...
iMappings.ReadLock();
TUint dummy;
DMemoryMapping* mapping = (DMemoryMapping*)iMappings.Find(aAddr,dummy);
if(mapping && mapping->IsAttached())
{
// found mapping, check addresses are in range...
TUint offset = aAddr-mapping->Base();
TUint end = offset+aSize;
if(offset<end && end<=mapping->iSizeInPages<<KPageShift)
{
// addresses OK, get a reference on the mapping before releasing list lock...
aOffsetInMapping = offset;
aInstanceCount = mapping->MapInstanceCount();
mapping->Open(); // can't fail because mapping IsAttached
result = mapping;
}
}
iMappings.ReadUnlock();
return result;
}
TBool DAddressSpace::CheckPdeType(TLinAddr aAddr, TUint aSize, TUint aPdeType)
{
TRACE(("DAddressSpace::CheckPdeType(0x%08x,0x%08x,%d) osAsid=%d",aAddr, aSize, aPdeType, iOsAsid));
TBool r;
Lock();
if(iOsAsid==(TInt)KKernelOsAsid && UserGlobalVirtualAllocator.InRange(aAddr,aSize))
r = UserGlobalVirtualAllocator.CheckSlabType(aAddr,aSize,aPdeType);
else
r = iVirtualAllocator.CheckSlabType(aAddr,aSize,aPdeType);
TRACE(("DAddressSpace::CheckPdeType returns %d",r));
Unlock();
return r;
}
//
// Debug
//
#ifdef _DEBUG
void DAddressSpace::Dump()
{
Kern::Printf("DAddressSpace[0x%08x]::Dump() osAsid = %d",this,iOsAsid);
TLinAddr virt = 0;
do
{
--virt;
iMappings.ReadLock();
TUint offsetInMapping = 0;
DMemoryMapping* mapping = (DMemoryMapping*)iMappings.Find(virt,offsetInMapping);
if(mapping)
{
if(!mapping->TryOpen())
mapping = NULL;
virt -= offsetInMapping;
}
iMappings.ReadUnlock();
if(!mapping)
break;
mapping->Dump();
mapping->Close();
}
while(virt);
}
#endif // _DEBUG