First public contribution.
1 // Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
2 // All rights reserved.
3 // This component and the accompanying materials are made available
4 // under the terms of the License "Eclipse Public License v1.0"
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
22 #include "cache_maintenance.inl"
25 // check enough space for page directories...
26 __ASSERT_COMPILE(KNumOsAsids <= (KPageDirectoryEnd-KPageDirectoryBase)/KPageDirectorySize);
29 PageDirectoryAllocator PageDirectories;
32 const TUint KLocalPdShift = KPageDirectoryShift > KPageShift ? KPageDirectoryShift-1 : KPageShift;
33 const TUint KLocalPdSize = 1<<KLocalPdShift;
34 const TUint KLocalPdPages = 1<<(KLocalPdShift-KPageShift);
37 __ASSERT_COMPILE((KPageDirectoryBase&(31*KPageDirectorySize))==0); // following code assumes this alignment
39 void PageDirectoryAllocator::GlobalPdeChanged(TPde* aPde)
41 __NK_ASSERT_DEBUG(MmuLock::IsHeld());
42 __NK_ASSERT_DEBUG(TLinAddr(aPde)>=KPageDirectoryBase);
43 __NK_ASSERT_DEBUG(TLinAddr(aPde)<KPageDirectoryEnd);
44 __NK_ASSERT_DEBUG(KLocalPdSize==(TUint)KPageDirectorySize); // shouldn't be called if we have separate global PDs
46 TLinAddr addr = (TLinAddr(aPde)&KPageDirectoryMask)*(KChunkSize/sizeof(TPde));
47 if(addr<KGlobalMemoryBase)
48 return; // change was in local part of PD, so nothing to do
49 if(addr-KIPCAlias<KIPCAliasAreaSize)
50 return; // change was in IPC alias area, so nothing to do
52 return; // not yet initialised
54 TRACE2(("PageDirectoryAllocator::GlobalPdeChanged(0x%08x)",aPde));
56 TLinAddr pPde = KPageDirectoryBase+(TLinAddr(aPde)&KPageDirectoryMask); // first page directory
58 // copy PDE to all allocated page directories
59 pPde -= KPageDirectorySize; // start off at PD minus one
60 TLinAddr lastPd = KPageDirectoryBase+(KNumOsAsids-1)*KPageDirectorySize;
61 TUint32* ptr = iAllocator->iMap;
64 TUint32 bits = ~*ptr++;
67 pPde += KPageDirectorySize; // step to next page directory
70 TRACE2(("!PDE %x=%x",pPde,pde));
72 CacheMaintenance::SinglePdeUpdated(pPde);
76 pPde |= 31*KPageDirectorySize; // step to next group of 32 PDs
82 void PageDirectoryAllocator::Init2()
84 TRACEB(("PageDirectoryAllocator::Init2()"));
86 // construct memory object for page directories...
87 #if defined(__CPU_PAGE_TABLES_FULLY_CACHED)
88 TMemoryAttributes memAttr = EMemoryAttributeStandard;
90 TMemoryAttributes memAttr = (TMemoryAttributes)(EMemoryAttributeNormalUncached|EMemoryAttributeDefaultShareable);
92 TInt r = MM::InitFixedKernelMemory(iPageDirectoryMemory, KPageDirectoryBase, KPageDirectoryEnd, KPageDirectorySize, EMemoryObjectHardware, EMemoryCreateNoWipe, memAttr, EMappingCreateFixedVirtual);
93 __NK_ASSERT_ALWAYS(r==KErrNone);
95 // initialise kernel page directory...
96 TPhysAddr kernelPd = Mmu::LinearToPhysical((TLinAddr)Mmu::PageDirectory(KKernelOsAsid));
97 iKernelPageDirectory = kernelPd;
98 ((DMemModelProcess*)K::TheKernelProcess)->iPageDir = kernelPd;
99 AssignPages(KKernelOsAsid*(KPageDirectorySize>>KPageShift),KPageDirectorySize>>KPageShift,kernelPd);
101 // construct allocator...
102 iAllocator = TBitMapAllocator::New(KNumOsAsids,ETrue);
103 __NK_ASSERT_ALWAYS(iAllocator);
104 iAllocator->Alloc(KKernelOsAsid,1); // kernel page directory already allocated
106 TRACEB(("PageDirectoryAllocator::Init2 done"));
110 void PageDirectoryAllocator::AssignPages(TUint aIndex, TUint aCount, TPhysAddr aPhysAddr)
112 __NK_ASSERT_DEBUG(aCount<=KMaxPageInfoUpdatesInOneGo);
114 SPageInfo* pi = SPageInfo::FromPhysAddr(aPhysAddr);
115 SPageInfo* piEnd = pi+aCount;
118 pi->SetPhysAlloc(iPageDirectoryMemory,aIndex);
126 TInt PageDirectoryAllocator::Alloc(TUint aOsAsid, TPhysAddr& aPageDirectory)
128 TRACE(("PageDirectoryAllocator::Alloc(%d)",aOsAsid));
130 // get memory for local page directory...
132 TUint offset = aOsAsid*KPageDirectorySize;
134 RamAllocLock::Lock();
135 TInt r = m.AllocContiguousRam(pdPhys, KLocalPdPages, KLocalPdShift-KPageShift, iPageDirectoryMemory->RamAllocFlags());
137 AssignPages(offset>>KPageShift,KLocalPdPages,pdPhys);
138 RamAllocLock::Unlock();
142 TRACE(("PageDirectoryAllocator::Alloc pdPhys = 0x%08x",pdPhys));
144 // map local page directory...
145 r = MM::MemoryAddContiguous(iPageDirectoryMemory,MM::BytesToPages(offset),KLocalPdPages,pdPhys);
148 RamAllocLock::Lock();
149 m.FreeContiguousRam(pdPhys,KLocalPdPages);
150 RamAllocLock::Unlock();
154 aPageDirectory = pdPhys;
156 TPde* pd = Mmu::PageDirectory(aOsAsid);
157 const TUint globalOffset = (KGlobalMemoryBase>>KChunkShift)*sizeof(TPde); // start of global part
159 // clear local entries in page directory...
160 memclr(pd,globalOffset);
161 CacheMaintenance::PdesInitialised((TLinAddr)pd,globalOffset);
163 if(KLocalPdSize<(TUint)KPageDirectorySize)
165 // map global page directory after local part...
166 __NK_ASSERT_DEBUG(KLocalPdSize==globalOffset);
167 r = MM::MemoryAddContiguous(iPageDirectoryMemory, MM::BytesToPages(offset+KLocalPdSize),
168 (KPageDirectorySize-KLocalPdSize)/KPageSize, iKernelPageDirectory+KLocalPdSize);
169 __NK_ASSERT_DEBUG(r==KErrNone); // can't fail
170 MmuLock::Lock(); // need lock because allocator not otherwise atomic
171 iAllocator->Alloc(aOsAsid,1);
176 // copy global entries to local page directory...
177 TPde* globalPd = Mmu::PageDirectory(KKernelOsAsid);
178 MmuLock::Lock(); // need lock because allocator not otherwise atomic, also to make sure GlobalPdeChanged() only accesses extant PDs
179 memcpy((TUint8*)pd+globalOffset,(TUint8*)globalPd+globalOffset,KPageDirectorySize-globalOffset);
180 iAllocator->Alloc(aOsAsid,1);
182 CacheMaintenance::PdesInitialised((TLinAddr)((TUint8*)pd+globalOffset),KPageDirectorySize-globalOffset);
186 TRACE(("PageDirectoryAllocator::Alloc returns %d",r));
191 void PageDirectoryAllocator::Free(TUint aOsAsid)
193 TRACE(("PageDirectoryAllocator::Free(%d)",aOsAsid));
195 MmuLock::Lock(); // need lock because allocator not otherwise atomic, also to make sure GlobalPdeChanged() only accesses extant PDs
196 iAllocator->Free(aOsAsid, 1);
199 const TUint KPageDirectoryPageCount = KPageDirectorySize>>KPageShift;
200 TPhysAddr pages[KPageDirectoryPageCount];
201 TUint n = MM::MemoryRemovePages(iPageDirectoryMemory,aOsAsid*KPageDirectoryPageCount,KPageDirectoryPageCount,pages);
203 __NK_ASSERT_DEBUG(n==KPageDirectoryPageCount);
205 RamAllocLock::Lock();
207 // Page directories are fixed.
208 m.FreeRam(pages, KLocalPdPages, EPageFixed);
209 RamAllocLock::Unlock();