diff -r 000000000000 -r a41df078684a kernel/eka/memmodel/epoc/multiple/mmu.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/memmodel/epoc/multiple/mmu.cpp Mon Oct 19 15:55:17 2009 +0100 @@ -0,0 +1,281 @@ +// Copyright (c) 1998-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\epoc\multiple\mmu.cpp +// +// + +#include "memmodel.h" +#include + +_LIT(KLitGlobalDollarCode,"GLOBAL$CODE"); + +/******************************************************************************* + * "Independent" MMU code + *******************************************************************************/ + +void Mmu::Panic(TPanic aPanic) + { + Kern::Fault("MMU",aPanic); + } + +TPde* Mmu::LocalPageDir(TInt aOsAsid) + { + __ASSERT_DEBUG(TUint32(aOsAsid)=iUserSharedEnd && (iAsidInfo[aOsAsid]&1)) + p=(TPde*)iPdeBase; + p+=(aAddr>>iChunkShift); + __KTRACE_OPT(KMMU,Kern::Printf("PDE(%08x,%d) at %08x",aAddr,aOsAsid,p)); + return *p; + } +*/ +TInt Mmu::NewOsAsid(TBool aSeparateGlobal) +// +// Allocate a new OS ASID and page directory. +// Map the page directory at the expected linear address and initialise it. +// + { + __KTRACE_OPT(KMMU,Kern::Printf("Mmu::NewOsAsid(%x)",aSeparateGlobal)); + TInt os_asid=iOsAsidAllocator->Alloc(); + if (os_asid<0) + return KErrNoMemory; + TPhysAddr pdPhys; + TInt pdPages=0; + TInt r=NewPageDirectory(os_asid,aSeparateGlobal,pdPhys,pdPages); + __KTRACE_OPT(KMMU,Kern::Printf("NewPageDirectory: %d %08x %d",r,pdPhys,pdPages)); + if (r!=KErrNone) + { + iOsAsidAllocator->Free(os_asid); + return KErrNoMemory; + } + TBool global=(pdPages<NotFree(os_asid+1,iAsidGroupMask)) ) + { + // expand page directory mapping + TInt xptid=AllocPageTable(); + if (xptid<0) + { + iRamPageAllocator->FreePhysicalRam(pdPhys,pdPages<Free(os_asid); + return KErrNoMemory; + } + AssignPageTable(xptid, SPageTableInfo::EGlobal, NULL, pdLin, iPdPdePerm); // map XPT + } + TInt i; + for (i=0; iFree(aOsAsid); + iNumGlobalPageDirs-=global; + TLinAddr pdLin=iPdeBase+(aOsAsid<>iPageShift); +#ifdef BTRACE_KERNEL_MEMORY + BTrace4(BTrace::EKernelMemory, BTrace::EKernelMemoryMiscFree, size); + Epoc::KernelMiscPages -= size>>iPageShift; +#endif + TInt asid_group=aOsAsid&~iAsidGroupMask; + if (!iOsAsidAllocator->NotFree(asid_group,iAsidGroupSize)) + { + // shrink page directory mapping + TInt xptid=PageTableId(pdLin,0); + DoUnassignPageTable(pdLin, GLOBAL_MAPPING); + FreePageTable(xptid); + } + } + +TPhysAddr Mmu::LinearToPhysical(TLinAddr aLinAddr) +// +// Find the physical address corresponding to a given linear address +// Call with system locked +// + { + DMemModelProcess* pP=(DMemModelProcess*)TheCurrentThread->iOwningProcess; + return LinearToPhysical(aLinAddr, pP->iOsAsid); + } + +TInt Mmu::LinearToPhysical(TLinAddr aLinAddr, TInt aSize, TPhysAddr& aPhysicalAddress, TPhysAddr* aPhysicalPageList) + { + DMemModelProcess* pP=(DMemModelProcess*)TheCurrentThread->iOwningProcess; + return LinearToPhysical(aLinAddr, aSize, aPhysicalAddress, aPhysicalPageList, pP->iOsAsid); + } + +TInt Mmu::PageTableId(TLinAddr aAddr) + { + DMemModelProcess* pP=(DMemModelProcess*)TheCurrentThread->iOwningProcess; + return PageTableId(aAddr, pP->iOsAsid); + } + +void Mmu::Init1() + { + __KTRACE_OPT2(KBOOT,KMMU,Kern::Printf("Mmu::Init1")); + iMaxPageTables=65535; // possibly reduced when RAM size known + memclr(iAsidInfo, iNumOsAsids*sizeof(TUint32)); + MmuBase::Init1(); + } + +void Mmu::CreateUserGlobalSection(TLinAddr aBase, TLinAddr aEnd) + { + iUserGlobalSection=TLinearSection::New(aBase, aEnd); + __ASSERT_ALWAYS(iUserGlobalSection,Panic(ECreateUserGlobalSectionFailed)); + } + +void Mmu::DoInit2() + { + __KTRACE_OPT2(KBOOT,KMMU,Kern::Printf("Mmu::DoInit2")); + iSharedSection=TLinearSection::New(iUserSharedBase, iUserSharedEnd); + __ASSERT_ALWAYS(iSharedSection,Panic(ECreateSharedSectionFailed)); + iOsAsidAllocator=TBitMapAllocator::New(iNumOsAsids,ETrue); + __ASSERT_ALWAYS(iOsAsidAllocator,Panic(EOsAsidAllocCreateFailed)); + iOsAsidAllocator->Alloc(0,1); // 0=kernel process + DMemModelProcess* pP=(DMemModelProcess*)K::TheKernelProcess; + if (iLocalPdSize) + pP->iLocalPageDir=LinearToPhysical(TLinAddr(LocalPageDir(0))); + pP->iGlobalPageDir=LinearToPhysical(TLinAddr(GlobalPageDir(0))); + __KTRACE_OPT(KMMU,Kern::Printf("Kernel process: LPD=%08x GPD=%08x",pP->iLocalPageDir,pP->iGlobalPageDir)); + MM::UserCodeAllocator=TBitMapAllocator::New(iMaxUserCodeSize>>iAliasShift, ETrue); // code is aligned to alias size + __ASSERT_ALWAYS(MM::UserCodeAllocator,Panic(EUserCodeAllocatorCreateFailed)); + MM::DllDataAllocator=TBitMapAllocator::New(iMaxDllDataSize>>iPageShift, ETrue); + __ASSERT_ALWAYS(MM::DllDataAllocator,Panic(EDllDataAllocatorCreateFailed)); + __ASSERT_ALWAYS(TheRomHeader().iUserDataAddress==iDllDataBase+iMaxDllDataSize,Panic(ERomUserDataAddressInvalid)); + __ASSERT_ALWAYS((TheRomHeader().iTotalUserDataSize&iPageMask)==0,Panic(ERomUserDataSizeInvalid)); + TInt rom_dll_pages=TheRomHeader().iTotalUserDataSize>>iPageShift; + __KTRACE_OPT2(KBOOT,KMMU,Kern::Printf("UserCodeAllocator @ %08x DllDataAllocator @ %08x, %d ROM DLL Data Pages", + MM::UserCodeAllocator, MM::DllDataAllocator, rom_dll_pages)); + if (rom_dll_pages) + MM::DllDataAllocator->Alloc(0, rom_dll_pages); // low bit numbers represent high addresses + } + +void Mmu::SetupInitialPageInfo(SPageInfo* aPageInfo, TLinAddr aChunkAddr, TInt aPdeIndex) + { + __ASSERT_ALWAYS(aChunkAddr>=iUserSharedEnd,Panic(EBadInitialPageAddr)); + TLinAddr addr=aChunkAddr+(aPdeIndex<Type()!=SPageInfo::EUnused) + return; // already set (page table) + if (addr==(TLinAddr)iPtInfo) + { + aPageInfo->SetPtInfo(0); + aPageInfo->Lock(); + } + else if (addr>=iPdeBase && addrSetPageDir(0,aPdeIndex); + aPageInfo->Lock(); + } + else + aPageInfo->SetFixed(); + } + +void Mmu::SetupInitialPageTableInfo(TInt aId, TLinAddr aChunkAddr, TInt aNumPtes) + { + __ASSERT_ALWAYS(aChunkAddr>=iUserSharedEnd || aChunkAddr==0,Panic(EBadInitialPageAddr)); + SPageTableInfo& pti=PtInfo(aId); + pti.iCount=aNumPtes; + pti.SetGlobal(aChunkAddr>>iChunkShift); + } + +void Mmu::AssignPageTable(TInt aId, TInt aUsage, TAny* aObject, TLinAddr aAddr, TPde aPdePerm) + { + __KTRACE_OPT(KMMU,Kern::Printf("Mmu::AssignPageTable id=%d, u=%08x, obj=%08x, addr=%08x, perm=%08x", + aId, aUsage, aObject, aAddr, aPdePerm)); + const TAny* asids=GLOBAL_MAPPING; + SPageTableInfo& pti=PtInfo(aId); + switch (aUsage) + { + case SPageTableInfo::EChunk: + { + DMemModelChunk* pC=(DMemModelChunk*)aObject; + TUint32 ccp=K::CompressKHeapPtr(pC); + TUint32 offset=(aAddr-TLinAddr(pC->iBase))>>iChunkShift; + pti.SetChunk(ccp,offset); + if (pC->iOsAsids) + asids=pC->iOsAsids; + else if (pC->iOwningProcess) + asids=(const TAny*)((DMemModelProcess*)pC->iOwningProcess)->iOsAsid; + break; + } +// case SPageTableInfo::EHwChunk: +// break; + case SPageTableInfo::EGlobal: + pti.SetGlobal(aAddr>>iChunkShift); + break; + default: + Panic(EAssignPageTableInvalidUsage); + } + DoAssignPageTable(aId, aAddr, aPdePerm, asids); + } + +TInt Mmu::UnassignPageTable(TLinAddr aAddr) + { + __KTRACE_OPT(KMMU,Kern::Printf("Mmu::UnassignPageTable addr=%08x", aAddr)); + TInt id=PageTableId(aAddr, 0); + if (id>=0) + DoUnassignPageTable(aAddr, GLOBAL_MAPPING); + return id; + } + +TInt Mmu::CreateGlobalCodeChunk() +// +// Enter and return with neither system lock nor MMU mutex held +// + { + __KTRACE_OPT(KDLL,Kern::Printf("Mmu::CreateGlobalCodeChunk")); + TInt maxsize=Min(TheSuperPage().iTotalRamSize/2, 0x01000000); + SChunkCreateInfo c; + c.iGlobal=ETrue; + c.iAtt=TChunkCreate::EDisconnected; + c.iForceFixed=EFalse; + c.iOperations=SChunkCreateInfo::EAdjust|SChunkCreateInfo::EAdd; + c.iRunAddress=0; + c.iPreallocated=0; + c.iType=EDll; + c.iMaxSize=maxsize; + c.iName.Set(KLitGlobalDollarCode); + c.iOwner=NULL; + c.iInitialBottom=0; + c.iInitialTop=0; + TLinAddr runAddr; + return K::TheKernelProcess->NewChunk((DChunk*&)iGlobalCode,c,runAddr); + }