author | Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com> |
Wed, 13 Oct 2010 16:04:24 +0300 | |
branch | RCL_3 |
changeset 294 | 039a3e647356 |
parent 257 | 3e88ff8f41d5 |
permissions | -rw-r--r-- |
0 | 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". |
|
7 |
// |
|
8 |
// Initial Contributors: |
|
9 |
// Nokia Corporation - initial contribution. |
|
10 |
// |
|
11 |
// Contributors: |
|
12 |
// |
|
13 |
// Description: |
|
14 |
// |
|
15 |
||
16 |
#include <plat_priv.h> |
|
17 |
#include "mm.h" |
|
18 |
#include "mmu.h" |
|
19 |
||
20 |
#include "maddressspace.h" |
|
21 |
#include "mpdalloc.h" |
|
22 |
#include "mmapping.h" |
|
23 |
||
24 |
||
25 |
||
26 |
/** |
|
27 |
Allocator for OS Address Space IDs (OS ASIDs). |
|
28 |
This is a simple bitmap allocator for KNumOsAsids integers with an |
|
29 |
associated mutex to guard against concurrency when allocating and |
|
30 |
freeing. |
|
31 |
*/ |
|
32 |
class OsAsidAllocator |
|
33 |
{ |
|
34 |
public: |
|
35 |
void Init2() |
|
36 |
{ |
|
37 |
iAllocator = TBitMapAllocator::New(KNumOsAsids,ETrue); |
|
38 |
__NK_ASSERT_ALWAYS(iAllocator); |
|
39 |
iAllocator->Alloc(KKernelOsAsid,1); // make kernel OS ASID already allocated |
|
40 |
} |
|
41 |
||
42 |
TInt Alloc() |
|
43 |
{ |
|
44 |
NKern::FMWait(&iLock); |
|
45 |
TInt osAsid = iAllocator->Alloc(); |
|
46 |
NKern::FMSignal(&iLock); |
|
47 |
if(osAsid<0) |
|
48 |
return KErrNoMemory; |
|
49 |
return osAsid; |
|
50 |
} |
|
51 |
||
52 |
void Free(TInt aOsAsid) |
|
53 |
{ |
|
54 |
NKern::FMWait(&iLock); |
|
55 |
iAllocator->Free(aOsAsid); |
|
56 |
NKern::FMSignal(&iLock); |
|
57 |
} |
|
58 |
||
59 |
private: |
|
60 |
TBitMapAllocator* iAllocator; |
|
61 |
NFastMutex iLock; |
|
62 |
} |
|
63 |
OsAsidAllocator; |
|
64 |
||
65 |
||
66 |
// |
|
67 |
// DAddressSpace |
|
68 |
// |
|
69 |
||
70 |
DAddressSpace KernelAddressSpace; ///< The kernel's address space object. |
|
71 |
||
72 |
__ASSERT_COMPILE(KKernelOsAsid==0); |
|
73 |
DAddressSpace* AddressSpace[KNumOsAsids] = { &KernelAddressSpace }; |
|
74 |
||
75 |
RVirtualAllocator DAddressSpace::UserGlobalVirtualAllocator; |
|
76 |
RBackwardsVirtualAllocator DAddressSpace::UserCommonVirtualAllocator; |
|
77 |
||
78 |
/** |
|
79 |
The read lock used for protecting the mappings container in address spaces (DAddressSpace::iMappings). |
|
80 |
A single global lock is used for all processes - this isn't required but it is the simplest |
|
81 |
implementation if we want to avoid the memory overhead of allocating a mutex per address space. |
|
82 |
*/ |
|
83 |
NFastMutex TheAddressSpaceMappingLock; |
|
84 |
||
85 |
||
86 |
/** |
|
87 |
A pool of mutexes which are used to protect an address space's virtual address allocation |
|
88 |
and acts as a write lock for the mappings container (DAddressSpace::iMappings). |
|
89 |
*/ |
|
90 |
DMutexPool AddressSpaceMutexPool; |
|
91 |
||
92 |
||
93 |
void DAddressSpace::Init2() |
|
94 |
{ |
|
95 |
// create allocator for ASIDs... |
|
96 |
OsAsidAllocator.Init2(); |
|
97 |
||
98 |
// construct the kernel's address space... |
|
99 |
TInt r = KernelAddressSpace.Construct(0, KKernelSectionBase, KKernelSectionEnd); |
|
100 |
__NK_ASSERT_ALWAYS(r==KErrNone); |
|
101 |
||
102 |
// mark primary i/o region as already allocated... |
|
103 |
__ASSERT_COMPILE(((KPrimaryIOBase|KPrimaryIOEnd)&KChunkMask)==0); // region must be chunk aligned to avoid PDE type conflicts with any new allocations |
|
104 |
TLinAddr addr; |
|
105 |
TUint size; |
|
106 |
r = KernelAddressSpace.AllocateVirtualMemory(addr,size,KPrimaryIOBase,KPrimaryIOEnd-KPrimaryIOBase,0); |
|
107 |
__NK_ASSERT_ALWAYS(r==KErrNone); |
|
108 |
||
109 |
// construct user global memory allocator... |
|
110 |
r = UserGlobalVirtualAllocator.Construct(KGlobalMemoryBase,KUserMemoryLimit,ENumVirtualAllocTypes,AddressSpace[KKernelOsAsid]->iLock); |
|
111 |
__NK_ASSERT_ALWAYS(r==KErrNone); |
|
112 |
||
113 |
// construct user common memory allocator (two slab types, one each for paged and unpaged memory)... |
|
114 |
r = UserCommonVirtualAllocator.Construct(KUserLocalDataBase,KUserLocalDataEnd,ENumVirtualAllocTypes,AddressSpace[KKernelOsAsid]->iLock); |
|
115 |
__NK_ASSERT_ALWAYS(r==KErrNone); |
|
116 |
||
117 |
// reserve virtual memory for XIP user code... |
|
118 |
TUint romDataSize = TheRomHeader().iTotalUserDataSize; |
|
119 |
TLinAddr romDataBase = TheRomHeader().iUserDataAddress-romDataSize; |
|
120 |
__NK_ASSERT_DEBUG(TheRomHeader().iUserDataAddress==KUserLocalDataEnd); |
|
121 |
if(romDataSize) |
|
122 |
{ |
|
123 |
r = UserCommonVirtualAllocator.Alloc(addr,size,romDataBase,romDataSize,0); |
|
124 |
__NK_ASSERT_ALWAYS(r==KErrNone); |
|
125 |
} |
|
126 |
} |
|
127 |
||
128 |
||
129 |
DAddressSpace::DAddressSpace() |
|
130 |
: iMappings(&TheAddressSpaceMappingLock,iLock) |
|
131 |
{ |
|
132 |
} |
|
133 |
||
134 |
||
135 |
TInt DAddressSpace::New(TPhysAddr& aPageDirectory) |
|
136 |
{ |
|
137 |
TRACE(("DAddressSpace::New(?)")); |
|
138 |
TInt r; |
|
139 |
TInt osAsid = OsAsidAllocator.Alloc(); |
|
140 |
if(osAsid<0) |
|
141 |
r = KErrNoMemory; |
|
142 |
else |
|
143 |
{ |
|
144 |
r = PageDirectories.Alloc(osAsid,aPageDirectory); |
|
145 |
if(r!=KErrNone) |
|
146 |
OsAsidAllocator.Free(osAsid); |
|
147 |
else |
|
148 |
{ |
|
149 |
DAddressSpace*& info = AddressSpace[osAsid]; |
|
150 |
__NK_ASSERT_DEBUG(!info); |
|
151 |
info = new DAddressSpace(); |
|
152 |
if(!info) |
|
153 |
{ |
|
154 |
PageDirectories.Free(osAsid); |
|
155 |
OsAsidAllocator.Free(osAsid); |
|
156 |
r = KErrNoMemory; |
|
157 |
} |
|
158 |
else |
|
159 |
{ |
|
160 |
r = info->Construct(osAsid,KUserLocalDataBase,KUserLocalDataEnd); |
|
161 |
if(r!=KErrNone) |
|
162 |
{ |
|
163 |
info->Close(); |
|
164 |
info = 0; |
|
165 |
} |
|
166 |
} |
|
167 |
} |
|
168 |
} |
|
169 |
||
170 |
if(r==KErrNone) |
|
171 |
r = osAsid; |
|
172 |
else |
|
173 |
aPageDirectory = KPhysAddrInvalid; |
|
174 |
||
175 |
TRACE(("DAddressSpace::New returns %d",r)); |
|
176 |
return r; |
|
177 |
} |
|
178 |
||
179 |
||
180 |
||
181 |
DAddressSpace::~DAddressSpace() |
|
182 |
{ |
|
183 |
TRACE(("DAddressSpace[0x%08x]::~DAddressSpace() osAsid = %d",this,iOsAsid)); |
|
184 |
#ifdef _DEBUG |
|
185 |
if(iMappings.Count()) |
|
186 |
Dump(); |
|
187 |
#endif |
|
188 |
__NK_ASSERT_DEBUG(iMappings.Count()==0); |
|
189 |
||
190 |
TInt osAsid = iOsAsid; |
|
191 |
AddressSpace[osAsid] = 0; |
|
192 |
PageDirectories.Free(osAsid); |
|
193 |
InvalidateTLBForAsid(osAsid); |
|
194 |
OsAsidAllocator.Free(osAsid); |
|
195 |
} |
|
196 |
||
197 |
||
198 |
TInt DAddressSpace::Construct(TInt aOsAsid, TLinAddr aStart, TLinAddr aEnd) |
|
199 |
{ |
|
200 |
TRACE(("DAddressSpace::Construct(%d,0x%08x,0x%08x)",aOsAsid,aStart,aEnd)); |
|
201 |
iOsAsid = aOsAsid; |
|
202 |
return iVirtualAllocator.Construct(aStart,aEnd,ENumVirtualAllocTypes,iLock); |
|
203 |
} |
|
204 |
||
205 |
||
206 |
void DAddressSpace::Lock() |
|
207 |
{ |
|
208 |
AddressSpaceMutexPool.Wait(iLock); |
|
209 |
} |
|
210 |
||
211 |
||
212 |
void DAddressSpace::Unlock() |
|
213 |
{ |
|
214 |
AddressSpaceMutexPool.Signal(iLock); |
|
215 |
} |
|
216 |
||
217 |
||
218 |
TInt DAddressSpace::AllocateVirtualMemory(TLinAddr& aAddr, TUint& aSize, TLinAddr aRequestedAddr, TUint aRequestedSize, TUint aPdeType) |
|
219 |
{ |
|
220 |
TRACE(("DAddressSpace::AllocateVirtualMemory(?,?,0x%08x,0x%08x,%d) osAsid=%d",aRequestedAddr,aRequestedSize,aPdeType,iOsAsid)); |
|
221 |
__NK_ASSERT_DEBUG(aPdeType<ENumVirtualAllocTypes); |
|
222 |
Lock(); |
|
223 |
TInt r = iVirtualAllocator.Alloc(aAddr,aSize,aRequestedAddr,aRequestedSize,aPdeType); |
|
224 |
if(r==KErrNone) |
|
225 |
Open(); |
|
226 |
Unlock(); |
|
227 |
TRACE(("DAddressSpace::AllocateVirtualMemory returns %d region=0x%08x+0x%08x",r,aAddr,aSize)); |
|
228 |
return r; |
|
229 |
} |
|
230 |
||
231 |
||
232 |
TInt DAddressSpace::AllocateUserGlobalVirtualMemory(TLinAddr& aAddr, TUint& aSize, TLinAddr aRequestedAddr, TUint aRequestedSize, TUint aPdeType) |
|
233 |
{ |
|
234 |
TRACE(("DAddressSpace::AllocateUserGlobalVirtualMemory(?,?,0x%08x,0x%08x,%d)",aRequestedAddr,aRequestedSize,aPdeType)); |
|
235 |
__NK_ASSERT_DEBUG(aPdeType<ENumVirtualAllocTypes); |
|
236 |
KernelAddressSpace.Lock(); |
|
237 |
TInt r = UserGlobalVirtualAllocator.Alloc(aAddr,aSize,aRequestedAddr,aRequestedSize,aPdeType); |
|
238 |
KernelAddressSpace.Unlock(); |
|
239 |
TRACE(("DAddressSpace::AllocateUserGlobalVirtualMemory returns %d region=0x%08x+0x%08x",r,aAddr,aSize)); |
|
240 |
return r; |
|
241 |
} |
|
242 |
||
243 |
||
244 |
void DAddressSpace::FreeVirtualMemory(TLinAddr aAddr, TUint aSize) |
|
245 |
{ |
|
246 |
TRACE(("DAddressSpace::FreeVirtualMemory(0x%08x,0x%08x) osAsid=%d",aAddr, aSize, iOsAsid)); |
|
247 |
Lock(); |
|
257 | 248 |
if(iOsAsid==(TInt)KKernelOsAsid && UserGlobalVirtualAllocator.InRange(aAddr,aSize)) |
0 | 249 |
UserGlobalVirtualAllocator.Free(aAddr,aSize); |
250 |
else |
|
257 | 251 |
{ |
0 | 252 |
iVirtualAllocator.Free(aAddr,aSize); |
257 | 253 |
AsyncClose(); |
254 |
} |
|
256
c1f20ce4abcf
Revision: 201035
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
255 |
Unlock(); |
0 | 256 |
} |
257 |
||
258 |
||
259 |
TInt DAddressSpace::AllocateUserCommonVirtualMemory(TLinAddr& aAddr, TUint& aSize, TLinAddr aRequestedAddr, TUint aRequestedSize, TUint aPdeType) |
|
260 |
{ |
|
261 |
TRACE(("DAddressSpace::AllocateUserCommonVirtualMemory(?,?,0x%08x,0x%08x,%d)",aRequestedAddr,aRequestedSize,aPdeType)); |
|
262 |
__NK_ASSERT_DEBUG(aPdeType<ENumVirtualAllocTypes); |
|
263 |
KernelAddressSpace.Lock(); |
|
264 |
TInt r = UserCommonVirtualAllocator.Alloc(aAddr,aSize,aRequestedAddr,aRequestedSize,aPdeType); |
|
265 |
KernelAddressSpace.Unlock(); |
|
266 |
TRACE(("DAddressSpace::AllocateUserCommonVirtualMemory returns %d region=0x%08x+0x%08x",r,aAddr,aSize)); |
|
267 |
return r; |
|
268 |
} |
|
269 |
||
270 |
||
271 |
void DAddressSpace::FreeUserCommonVirtualMemory(TLinAddr aAddr, TUint aSize) |
|
272 |
{ |
|
273 |
TRACE(("DAddressSpace::FreeUserCommonVirtualMemory(0x%08x,0x%08x)",aAddr,aSize)); |
|
274 |
KernelAddressSpace.Lock(); |
|
275 |
UserCommonVirtualAllocator.Free(aAddr,aSize); |
|
276 |
KernelAddressSpace.Unlock(); |
|
277 |
} |
|
278 |
||
279 |
||
280 |
TInt DAddressSpace::AddMapping(TLinAddr aAddr, DMemoryMapping* aMapping) |
|
281 |
{ |
|
282 |
Lock(); |
|
283 |
TRACE(("DAddressSpace::AddMapping(0x%08x,0x%08x) osAsid=%d",aAddr, aMapping, iOsAsid)); |
|
284 |
TInt r = iMappings.Add(aAddr,aMapping); |
|
285 |
TRACE(("DAddressSpace::AddMapping osAsid=%d returns %d",iOsAsid, r)); |
|
286 |
Unlock(); |
|
287 |
return r; |
|
288 |
} |
|
289 |
||
290 |
||
291 |
DMemoryMapping* DAddressSpace::RemoveMapping(TLinAddr aAddr) |
|
292 |
{ |
|
293 |
Lock(); |
|
294 |
DMemoryMapping* removed = (DMemoryMapping*)iMappings.Remove(aAddr); |
|
295 |
TRACE(("DAddressSpace::RemoveMapping(0x%08x) osAsid=%d returns 0x%08x",aAddr, iOsAsid, removed)); |
|
296 |
Unlock(); |
|
297 |
return removed; |
|
298 |
} |
|
299 |
||
300 |
||
301 |
DMemoryMapping* DAddressSpace::GetMapping(TLinAddr aAddr) |
|
302 |
{ |
|
303 |
iMappings.ReadLock(); |
|
304 |
DMemoryMapping* mapping = (DMemoryMapping*)iMappings.Find(aAddr); |
|
305 |
TRACE(("DAddressSpace::GetMapping(0x%08x) osAsid=%d returns 0x%08x",aAddr, iOsAsid, mapping)); |
|
306 |
__NK_ASSERT_DEBUG(mapping); // caller must know there is a mapping |
|
307 |
iMappings.ReadUnlock(); |
|
308 |
return mapping; |
|
309 |
} |
|
310 |
||
311 |
||
312 |
DMemoryMapping* DAddressSpace::FindMapping(TLinAddr aAddr, TUint aSize, TUint& aOffsetInMapping, TUint& aInstanceCount) |
|
313 |
{ |
|
314 |
__ASSERT_CRITICAL; |
|
315 |
||
316 |
DMemoryMapping* result = NULL; |
|
317 |
||
318 |
// find mapping... |
|
319 |
iMappings.ReadLock(); |
|
320 |
TUint dummy; |
|
321 |
DMemoryMapping* mapping = (DMemoryMapping*)iMappings.Find(aAddr,dummy); |
|
322 |
if(mapping && mapping->IsAttached()) |
|
323 |
{ |
|
324 |
// found mapping, check addresses are in range... |
|
325 |
TUint offset = aAddr-mapping->Base(); |
|
326 |
TUint end = offset+aSize; |
|
327 |
if(offset<end && end<=mapping->iSizeInPages<<KPageShift) |
|
328 |
{ |
|
329 |
// addresses OK, get a reference on the mapping before releasing list lock... |
|
330 |
aOffsetInMapping = offset; |
|
331 |
aInstanceCount = mapping->MapInstanceCount(); |
|
332 |
mapping->Open(); // can't fail because mapping IsAttached |
|
333 |
result = mapping; |
|
334 |
} |
|
335 |
} |
|
336 |
iMappings.ReadUnlock(); |
|
337 |
||
338 |
return result; |
|
339 |
} |
|
340 |
||
341 |
||
342 |
TBool DAddressSpace::CheckPdeType(TLinAddr aAddr, TUint aSize, TUint aPdeType) |
|
343 |
{ |
|
344 |
TRACE(("DAddressSpace::CheckPdeType(0x%08x,0x%08x,%d) osAsid=%d",aAddr, aSize, aPdeType, iOsAsid)); |
|
345 |
TBool r; |
|
346 |
Lock(); |
|
347 |
if(iOsAsid==(TInt)KKernelOsAsid && UserGlobalVirtualAllocator.InRange(aAddr,aSize)) |
|
348 |
r = UserGlobalVirtualAllocator.CheckSlabType(aAddr,aSize,aPdeType); |
|
349 |
else |
|
350 |
r = iVirtualAllocator.CheckSlabType(aAddr,aSize,aPdeType); |
|
351 |
TRACE(("DAddressSpace::CheckPdeType returns %d",r)); |
|
352 |
Unlock(); |
|
353 |
return r; |
|
354 |
} |
|
355 |
||
356 |
||
357 |
||
358 |
// |
|
359 |
// Debug |
|
360 |
// |
|
361 |
||
362 |
#ifdef _DEBUG |
|
363 |
||
364 |
void DAddressSpace::Dump() |
|
365 |
{ |
|
366 |
Kern::Printf("DAddressSpace[0x%08x]::Dump() osAsid = %d",this,iOsAsid); |
|
367 |
TLinAddr virt = 0; |
|
368 |
do |
|
369 |
{ |
|
370 |
--virt; |
|
371 |
iMappings.ReadLock(); |
|
372 |
TUint offsetInMapping = 0; |
|
373 |
DMemoryMapping* mapping = (DMemoryMapping*)iMappings.Find(virt,offsetInMapping); |
|
374 |
if(mapping) |
|
375 |
{ |
|
376 |
if(!mapping->TryOpen()) |
|
377 |
mapping = NULL; |
|
378 |
virt -= offsetInMapping; |
|
379 |
} |
|
380 |
iMappings.ReadUnlock(); |
|
381 |
if(!mapping) |
|
382 |
break; |
|
383 |
mapping->Dump(); |
|
384 |
mapping->Close(); |
|
385 |
} |
|
386 |
while(virt); |
|
387 |
} |
|
388 |
||
389 |
#endif // _DEBUG |