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 "memmodel.h" sl@0: #include "mm.h" sl@0: #include "mmu.h" sl@0: sl@0: #include "mpdalloc.h" sl@0: #include "mobject.h" sl@0: #include "cache_maintenance.inl" sl@0: sl@0: sl@0: // check enough space for page directories... sl@0: __ASSERT_COMPILE(KNumOsAsids <= (KPageDirectoryEnd-KPageDirectoryBase)/KPageDirectorySize); sl@0: sl@0: sl@0: PageDirectoryAllocator PageDirectories; sl@0: sl@0: sl@0: const TUint KLocalPdShift = KPageDirectoryShift > KPageShift ? KPageDirectoryShift-1 : KPageShift; sl@0: const TUint KLocalPdSize = 1<=KPageDirectoryBase); sl@0: __NK_ASSERT_DEBUG(TLinAddr(aPde)iMap; sl@0: do sl@0: { sl@0: TUint32 bits = ~*ptr++; sl@0: do sl@0: { sl@0: pPde += KPageDirectorySize; // step to next page directory sl@0: if(bits&0x80000000u) sl@0: { sl@0: TRACE2(("!PDE %x=%x",pPde,pde)); sl@0: *(TPde*)pPde = pde; sl@0: CacheMaintenance::SinglePdeUpdated(pPde); sl@0: } sl@0: } sl@0: while(bits<<=1); sl@0: pPde |= 31*KPageDirectorySize; // step to next group of 32 PDs sl@0: } sl@0: while(pPdeiPageDir = kernelPd; sl@0: AssignPages(KKernelOsAsid*(KPageDirectorySize>>KPageShift),KPageDirectorySize>>KPageShift,kernelPd); sl@0: sl@0: // construct allocator... sl@0: iAllocator = TBitMapAllocator::New(KNumOsAsids,ETrue); sl@0: __NK_ASSERT_ALWAYS(iAllocator); sl@0: iAllocator->Alloc(KKernelOsAsid,1); // kernel page directory already allocated sl@0: sl@0: TRACEB(("PageDirectoryAllocator::Init2 done")); sl@0: } sl@0: sl@0: sl@0: void PageDirectoryAllocator::AssignPages(TUint aIndex, TUint aCount, TPhysAddr aPhysAddr) sl@0: { sl@0: __NK_ASSERT_DEBUG(aCount<=KMaxPageInfoUpdatesInOneGo); sl@0: MmuLock::Lock(); sl@0: SPageInfo* pi = SPageInfo::FromPhysAddr(aPhysAddr); sl@0: SPageInfo* piEnd = pi+aCount; sl@0: while(piSetPhysAlloc(iPageDirectoryMemory,aIndex); sl@0: ++pi; sl@0: ++aIndex; sl@0: } sl@0: MmuLock::Unlock(); sl@0: } sl@0: sl@0: sl@0: TInt PageDirectoryAllocator::Alloc(TUint aOsAsid, TPhysAddr& aPageDirectory) sl@0: { sl@0: TRACE(("PageDirectoryAllocator::Alloc(%d)",aOsAsid)); sl@0: sl@0: // get memory for local page directory... sl@0: Mmu& m = TheMmu; sl@0: TUint offset = aOsAsid*KPageDirectorySize; sl@0: TPhysAddr pdPhys; sl@0: RamAllocLock::Lock(); sl@0: TInt r = m.AllocContiguousRam(pdPhys, KLocalPdPages, KLocalPdShift-KPageShift, iPageDirectoryMemory->RamAllocFlags()); sl@0: if(r==KErrNone) sl@0: AssignPages(offset>>KPageShift,KLocalPdPages,pdPhys); sl@0: RamAllocLock::Unlock(); sl@0: sl@0: if(r==KErrNone) sl@0: { sl@0: TRACE(("PageDirectoryAllocator::Alloc pdPhys = 0x%08x",pdPhys)); sl@0: sl@0: // map local page directory... sl@0: r = MM::MemoryAddContiguous(iPageDirectoryMemory,MM::BytesToPages(offset),KLocalPdPages,pdPhys); sl@0: if(r!=KErrNone) sl@0: { sl@0: RamAllocLock::Lock(); sl@0: m.FreeContiguousRam(pdPhys,KLocalPdPages); sl@0: RamAllocLock::Unlock(); sl@0: } sl@0: else sl@0: { sl@0: aPageDirectory = pdPhys; sl@0: sl@0: TPde* pd = Mmu::PageDirectory(aOsAsid); sl@0: const TUint globalOffset = (KGlobalMemoryBase>>KChunkShift)*sizeof(TPde); // start of global part sl@0: sl@0: // clear local entries in page directory... sl@0: memclr(pd,globalOffset); sl@0: CacheMaintenance::PdesInitialised((TLinAddr)pd,globalOffset); sl@0: sl@0: if(KLocalPdSize<(TUint)KPageDirectorySize) sl@0: { sl@0: // map global page directory after local part... sl@0: __NK_ASSERT_DEBUG(KLocalPdSize==globalOffset); sl@0: r = MM::MemoryAddContiguous(iPageDirectoryMemory, MM::BytesToPages(offset+KLocalPdSize), sl@0: (KPageDirectorySize-KLocalPdSize)/KPageSize, iKernelPageDirectory+KLocalPdSize); sl@0: __NK_ASSERT_DEBUG(r==KErrNone); // can't fail sl@0: MmuLock::Lock(); // need lock because allocator not otherwise atomic sl@0: iAllocator->Alloc(aOsAsid,1); sl@0: MmuLock::Unlock(); sl@0: } sl@0: else sl@0: { sl@0: // copy global entries to local page directory... sl@0: TPde* globalPd = Mmu::PageDirectory(KKernelOsAsid); sl@0: MmuLock::Lock(); // need lock because allocator not otherwise atomic, also to make sure GlobalPdeChanged() only accesses extant PDs sl@0: memcpy((TUint8*)pd+globalOffset,(TUint8*)globalPd+globalOffset,KPageDirectorySize-globalOffset); sl@0: iAllocator->Alloc(aOsAsid,1); sl@0: MmuLock::Unlock(); sl@0: CacheMaintenance::PdesInitialised((TLinAddr)((TUint8*)pd+globalOffset),KPageDirectorySize-globalOffset); sl@0: } sl@0: } sl@0: } sl@0: TRACE(("PageDirectoryAllocator::Alloc returns %d",r)); sl@0: return r; sl@0: } sl@0: sl@0: sl@0: void PageDirectoryAllocator::Free(TUint aOsAsid) sl@0: { sl@0: TRACE(("PageDirectoryAllocator::Free(%d)",aOsAsid)); sl@0: sl@0: MmuLock::Lock(); // need lock because allocator not otherwise atomic, also to make sure GlobalPdeChanged() only accesses extant PDs sl@0: iAllocator->Free(aOsAsid, 1); sl@0: MmuLock::Unlock(); sl@0: sl@0: const TUint KPageDirectoryPageCount = KPageDirectorySize>>KPageShift; sl@0: TPhysAddr pages[KPageDirectoryPageCount]; sl@0: TUint n = MM::MemoryRemovePages(iPageDirectoryMemory,aOsAsid*KPageDirectoryPageCount,KPageDirectoryPageCount,pages); sl@0: (void)n; sl@0: __NK_ASSERT_DEBUG(n==KPageDirectoryPageCount); sl@0: sl@0: RamAllocLock::Lock(); sl@0: Mmu& m = TheMmu; sl@0: // Page directories are fixed. sl@0: m.FreeRam(pages, KLocalPdPages, EPageFixed); sl@0: RamAllocLock::Unlock(); sl@0: } sl@0: